## springBoot 学习
### 琐碎知识点
1. application.properties和application.yml是互补关系 而且前者比后者优先级高
2. 配置文件的优先级 是和源码中的ConfigFileApplicationListener类中定义的
优先级从后往前依次降低
> private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
3. 加载外部配置文件
<!-- more -->
> java -jar xxx.jar --spring.config.location=文件地址
4. https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/appendix-application-properties.html#core-properties properties文件的配置
5. spring boot 启动时会加载大量的自动配置类 ,但是例如mybatis 和driud没有自动配置类 ,需要去maven仓库找相应的springboot starter 或者是自己去写配置文件
6. 四大作用域 request < session < application
Spring Boot是一个快速开发框架,可以迅速的搭建出一套基于Spring框架体系的应用,是Spring Cloud的基础
spring boot开启了各种自动装配,从而简化代码的开发,不需要编写各种配置文件,只需要引入相关依赖就可以迅速搭建一个应用
7. 重定向会发生地址栏信息的跳转,请求转发不会
### springboot的注解
#### `@RequestMapping`
##### 基本介绍
Spring MVC 通过@RequestMapping注解将URL请求和业务方法进行映射,在Handler的类定义处以及方法的定义处都可以添加,在类定义处添加,相当于客户端多了一层访问路径
下边这个例子中 需要访问 localhost:8080/hello/index 才能成功访问
```java
//src/main/java/tech/haonan/controller/HelloHandler
package tech.haonan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/hello")
public class HelloHandler {
@RequestMapping("/index")
public String index(){
System.out.println("执行了index...");
return "index";
}
}
```
##### `@RequestMapping`相关参数
1. value: 指定URL请求的实际地址
```java
//src/main/java/tech/haonan/controller/HelloHandler
@RequestMapping("/hello")
//两者一样
@RequestMapping(value="/hello")
```
2. method:指定请求的method类型,GET,POST,PUT,DELETE
默认是get 和 post都行
```java
//src/main/java/tech/haonan/controller/HelloHandler
@RequestMapping(value="/hello" , method = RequestMethod.GET)
@RequestMapping(value="/hello" , method = RequestMethod.POST)
```
3. params : 指定请求中必须包含某些字段,否则没法访问
```java
//src/main/java/tech/haonan/controller/HelloHandler
@RequestMapping(value="/hello" , method = RequestMethod.GET,params = {"name","id=10"})
```
如果没有name和id字段 且id不等于10 就会出现以下报错
```shell
HTTP Status 400 – 错误的请求
Type Status Report
消息 Parameter conditions "name, id=10" not met for actual request parameters: name={daaf}, id={11}
描述 由于被认为是客户端对错误(例如:畸形的请求语法、无效的请求信息帧或者虚拟的请求路由),服务器无法或不会处理当前请求。
```
Servlet中需要传进来request参数 这里不再需要 你想要什么参数直接取就行
就像下边两行name是对应的
> @RequestMapping(value="/hello" , method = RequestMethod.GET,params = {"name","id=10"})
>
> public String index(String name)
```java
//src/main/java/tech/haonan/controller/HelloHandler
package tech.haonan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping(value="/hello" , method = RequestMethod.GET,params = {"name","id=10"})
public class HelloHandler {
@RequestMapping("/index")
public String index(String name){
System.out.println(name);
System.out.println("执行了index...");
return "index";
}
}
```
4. produces选项可以设置response返回值得编码 如果没有这一句,返回信息会出现中文乱码
```java
@RequestMapping(value = "/data",produces = "application/json; charset=utf-8")
```
#### `@RequestParam`
1. value 属性
2. required属性 设置一个参数是否是必须传入的 传就会抛异常
3. defaultValue 属性 给一个属性设置默认值
通过在形参列表中添加@RequestParam注解完成HTTP请求参数和业务方法形参的映射
也可以重新创建映射关系
```java
//src/main/java/tech/haonan/controller/HelloHandler
@RequestMapping(value="/hello" , method = RequestMethod.GET,params = {"name","id=10"})
public String index(@RequestParam(value="name") String str){
//这里就是把以前的name取了个别名 str
```
```java
//src/main/java/tech/haonan/controller/HelloHandler
package tech.haonan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/baseType")
@ResponseBody
public String baseType(@RequestParam(value = "num",required = true,defaultValue = "1") int id){//这里传入参数的时候必须是xxx:端口号/data/baseType?num=xxx
return id+"";
}
}
```
#### `@Controller`
`@Controller` 在类的定义处添加,将他交给IoC容器来管理(结合springmvc.xml中的自动扫描配置来实现),同时使类变成一个控制器,可以接收客户端请求。
#### `@RestController`
这个注解和下边的`@ResponseBody`和 `@ResponseBody`是一个东西
用于在类的上边添加 那么类的所有方法都不会寻找视图了 直接返回
```java
//src/main/java/tech/haonan/controller/HelloHandler
package tech.haonan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
@Controller
@RestController
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("array")
public String array(String[] name){
String str = Arrays.toString(name);
return str;
}
}
```
#### `@RequestBody`
RequestBody的作用是接受前端的json数据
而下边ResponseBody的作用是返回json数据
```java
@RequestMapping(value = "/json",produces = "application/json; charset=utf-8")
public User json(@RequestBody User user){
}
```
#### `@ResponseBody`
下边代码的`return id+"";` 因为有了`@ResponseBody`注解所以不再寻找id.jsp文件了
直接在页面上返回你之前输入的id 到网页上 因为int值不能是null所以如果你之前没有传值进去 那么服务器就会报错 所以使用int的包装类Integer 就非常有必要
以前的代码都是`return "index";` 他会直接根据springmvc.xml中的下面两行代码寻找jsp文件
><property name="prefix" value="/"></property>
><property name="suffix" value=".jsp"></property>
这样他就会寻找 `index.jsp` 文件
```java
//src/main/java/tech/haonan/controller/HelloHandler
@Controller
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/baseType")
@ResponseBody
public String baseType(int id){
return id+"";
}
}
```
#### `@Configuration`
作用在类上相当于一个xml配置文件
#### `@Bean`
作用于方法上,相当于xml配置中的`<bean>`
创建 实体类User
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private String address;
}
```
添加配置类
```java
@Configuration
public class JavaConfigA {
//这里相当于添加了一个bean 和下边代码效果一致
/*
<bean id="User" class="tech.haonan.entity.User">
<property name="id" value="1"></property>
<property name="name" value="小明"></property>
<property name="address" value="山东省"></property>
</bean>
*/
@Bean
public User getUser1(){
return new User(1,"小明","山东省");
}
}
```
调用test类测试
```java
@SpringBootTest
class ApplicationTests {
@Autowired
private User user;
@Test
void contextLoads() {
System.out.println(user);
//这里输出 User(id=1, name=小明, address=山东省)
}
}
```
#### `@Import`
在创建配置文件后可以用来引入其他的配置文件
如果一个配置文件没有加`@Configuration` 那么可以使用@Import 来引入
```java
//JavaConfigA 文件 注意没有@Configuration注解
public class JavaConfigA {
@Bean
public User getUser1(){
return new User(1,"小明","山东省");
}
}
```
```java
//JavaConfigB 文件
@Configuration
@Import({JavaConfigA.class})
public class JavaConfigB {
}
```
#### `@ComponentScan`
配置扫描 下面是文件结构
```shell
├── 01_springboot.iml
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
│ ├── java
│ │ ├── aaa
│ │ │ └── Config.java //配置类
│ │ └── tech
│ │ └── haonan
│ │ ├── Application.java //启动类
│ │ └── entity
│ │ └── User.java //实体类
│ └── resources
│ ├── application.properties
│ ├── static
│ └── templates
└── test
└── java
└── tech
└── haonan
└── ApplicationTests.java //测试类
```
启动类可以添加 如果不添加 那么会导致测试类报错
```java
@SpringBootApplication
@ComponentScan("aaa")
@RestController
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
测试类
```java
@SpringBootTest
class ApplicationTests {
@Autowired
private User user;
@Test
void contextLoads() {
System.out.println(user);
}
}
```
#### `@Qualifier`
多个同样的类时可以用于挑选想要的类
配置文件中有两个类 会发现test类调用的时候报错
```java
@Component
@Configuration
public class Config {
@Bean("user1")
public User getUser1(){
return new User(1,"小明","山东省");
}
@Bean("user2")
public User getUser2(){
return new User(2,"444","5555");
}
}
```
test类 `@Qualifier("user1")` 这里指定了bean对象
```java
@SpringBootTest
@ComponentScan(basePackageClasses = Config.class)
class ApplicationTests {
@Autowired
@Qualifier("user1")
private User user;
@Test
void contextLoads() {
System.out.println(user);
}
}
```
#### `@Primary`
`@Primary` 这里指定了bean对象
```java
@Component
@Configuration
public class Config {
@Primary
@Bean("user1")
public User getUser1(){
return new User(1,"小明","山东省");
}
@Bean("user2")
public User getUser2(){
return new User(2,"444","5555");
}
}
```
test类
```java
@SpringBootTest
class ApplicationTests {
@Autowired
private User user;
@Test
void contextLoads() {
System.out.println(user);
}
}
```
#### `@ConfigurationProperties`
目录结构
```shell
yhn@yhn-PC:/project/javaProject/01_springboot$ tree ./
./
├── 01_springboot.iml
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── tech
│ │ └── haonan
│ │ ├── Application.java
│ │ ├── config
│ │ │ └── StudentAutoConfig.java
│ │ └── entity
│ │ └── Student.java
│ └── resources
│ ├── application.properties
│ ├── static
│ └── templates
└── test
└── java
└── tech
└── haonan
└── ApplicationTests.java
```
下面代码中新添了一个`@ConfigurationProperties(prefix = "student")` 表示可以在application.properties文件中注入bean
- 作用在类上
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@ConfigurationProperties(prefix = "student")
public class Student {
private Integer id;
private String name;
private String[] hobby;
private List<String> lists;
private Map<String,String> maps;
private Set<String> sets;
private Integer age;
private Date birth;
}
```
- 作用在方法上
```java
@Configuration
public class StudentAutoConfig {
@Bean
@ConfigurationProperties("student")
public Student getStudent(){
return new Student();
}
}
```
application.properties的配置
配置文件的占位符
```
${random.int}生成随机数
${random.value}生成随机字符串
${random.long}生成一个long的随机数据
${random.int(10)}生成0-10的随机int数
${random.int(10,20)}生成10-20的随机数
```
```properties
student.birth=2020/1/18
student.hobby=aaa,bbb,ccc,ddd,aaa
student.maps.a1 =a1
student.maps.a2 =a2
student.maps.a3 =a3
student.sets=aaa,bbb,ccc,ddd,aaa
student.id=${bbbb.age}
student.age=${cccc.age}
student.name=张三
bbbb.age=10
cccc.age=${random.int(1,100)}
dddd.age=${random.long(1.555)}
```
测试类输出
```java
@SpringBootTest
class ApplicationTests {
@Autowired
private Student student;
@Test
void contextLoads() {
System.out.println(student);
//输出
/*
Student(id=10, name=null, hobby=[aaa, bbb, ccc, ddd, aaa], lists=null, maps={a1=a1, a2=a2, a3=a3}, sets=[aaa, bbb, ccc, ddd], age=null, birth=Sat Jan 18 00:00:00 CST 2020)
*/
}
}
```
#### `@value`
这个和上边的`@ConfigurationProperties`功能一致 ,但是区别是value是主动注入,而ConfigurationProperties是被动注入
下面是例子
```yml
#application.yml
student:
id: ${random.int(1,100)}
birth: 2020/1/18
hobby:
1
2
3
lists:
aaa
bbb
ccc
ddd
```
```java
//实体类Student
package tech.haonan.entity;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
@Value("${student.id}")
private Integer id;
private String name;
@Value("${student.hobby}")
private String[] hobby;
@Value("${student.lists}")
private List<String> lists;
private Map<String,String> maps;
private Set<String> sets;
private Integer age;
@Value("${student.birth}")
private Date birth;
}
```
测试类中输出
```java
@SpringBootTest
class ApplicationTests {
@Autowired
private Student student;
@Test
void contextLoads() {
System.out.println(student);
}
}
//Student(id=50, name=null, hobby=[1 2 3], lists=[aaa bbb ccc ddd], maps=null, sets=null, age=null, birth=Sat Jan 18 00:00:00 CST 2020)
```
注意点 :
1. application.yml和application.properties 中不能使用Map集合
#### `@Validated`
Validated 是加在类上的注解 可以进行嵌套使用 类中类也可加
格式是
```java
@Validated
class xxx{
@NotNull
private Integer a;
}
```
```
空检查
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.
Booelan检查
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) Validates that the annotated string is between min and max included.
日期检查
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) Checks whether the annotated value lies between (inclusive) the specified minimum and maximum.
@Range(min=10000,max=50000,message="range.bean.wage")
private BigDecimal wage;
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
```
#### `@PropertySource`
可以指定配置文件的别名 不非得是application.properties
可以放在启动类上 也可以放在实体类上
```java
//启动类
@SpringBootApplication
@RestController
@PropertySource(value = {"classpath:/student.properties"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
```java
//实体类 需要加@component注解才能注入
@Data
@AllArgsConstructor
@NoArgsConstructor
@PropertySource(value = {"classpath:/student.properties"})
@ConfigurationProperties(prefix = "student")
public class Student {
private Integer id;
private String name;
private String[] hobby;
private List<String> lists;
private Map<String,String> maps;
private Set<String> sets;
private Integer age;
private Date birth;
private String userName;
}
```
注意事项 : application.properties 的优先级还是要高于自己的配置文件 配置文件可以放在任意位置 不一定非得是classpath
#### `@ImportResource`
实体类Student
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
}
```
在`resource`目录下创建`beans.xml`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="tech.haonan.entity.Student">
<property name="id" value="100"></property>
<property name="name" value="张三"></property>
</bean>
</beans>
```
启动类中引用
```java
@SpringBootApplication
@RestController
@ImportResource(value = {"classpath:beans.xml"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
然后测试类中就可以进行调用了 student类就会自动装填上去
#### `@Profile`
##### 几点说明
profile 文件是用来区别开发环境和测试环境的
创建 application-dev.properties application-dev.properties 文件
在application.properties中添加
> spring.profiles.active=pro
这样执行的是 application-dev.properties的内容,文件名称横杠后边的内容(application-xxx.properties 即xxx)和spring.profiles.active = 后边的内容应该一致
##### 实例
目录结构
```shell
yhn@yhn-PC:/project/javaProject/01_springboot$ tree demo/
demo/
├── demo.iml
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── demo
│ │ │ ├── DemoApplication.java
│ │ │ ├── entity
│ │ │ │ └── User.java
│ │ │ └── UserConfig.java
│ │ └── resources
│ │ ├── application-dev.properties
│ │ ├── application.properties
│ │ ├── application-pro.properties
│ │ ├── static
│ │ └── templates
│ └── test
│ └── java
│ └── com
│ └── example
│ └── demo
│ └── DemoApplicationTests.java
```
user实体类
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
}
```
config 文件
confIg 文件中就用到了`@Profile`注解 这里可以选择bean的注入是选择哪个配置文件
```java
//userConfig.java 文件
@Configuration
public class UserConfig {
@Bean
@Profile(value = "dev")
public User getUser1(){
return new User(1,"developer");
}
@Bean
@Profile(value = "pro")
public User getUser2(){
return new User(2,"product");
}
}
```
application.properties
```properties
spring.profiles.active=dev
```
test类
这里的test类中的属性就是1,"developer" 如果 properties 文件改为 spring.profiles.active=pro 那么就是2,"product"
```java
@SpringBootTest
class DemoApplicationTests {
@Autowired
User user;
@Test
void contextLoads() {
System.out.println(user);
}
}
```
#### `@Condition`
这个是用来让spring来判断当前配置是否生效的注解 相当于if语句 类型有很多 就不一一举例了
```
ConditionalOnBean
ConditionalOnClass
ConditionalOnCloudPlatform
```
使用实例
`@ConditionalOnJava`用来判断jdk版本是不是java11
```java
@Configuration
@ConditionalOnJava(value = JavaVersion.ELEVEN)
public class UserConfig {
@Bean
@Profile(value = "dev")
public User getUser1(){
return new User(1,"developer");
}
@Bean
@Profile(value = "pro")
public User getUser2(){
return new User(2,"product");
}
}
```
### springboot特点
1. 不需要web.xml
2. 不需要springmvc.xml
3. 不需要tomcat,SpringBoot内嵌了tomcat
4. 不需要配置JSON解析,支持REST架构
5. 个性化配置非常简单
### springboot的快速启动
注意这里的项目只是一个小demo 没有调用数据库
#### 0.目录结构
```shell
yhn@yhn-PC:/project/javaProject/springboot$ tree ./
./
├── pom.xml
├── springboot.iml
└── src
├── main
│ ├── java
│ │ └── tech
│ │ └── haonan
│ │ ├── Application.java
│ │ ├── controller
│ │ │ └── StudentHandler.java
│ │ ├── entity
│ │ │ └── Student.java
│ │ └── repository
│ │ ├── Impl
│ │ │ └── StudentRepositoryImpl.java
│ │ └── StudentRepository.java
│ └── resources
│ └── application.yml
└── test
└── java
```
#### 1.创建maven工程
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>tech.haonan</groupId>
<artifactId>springboot</artifactId>
<version>1.0-SNAPSHOT</version>
<!--继承父包-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
</parent>
<dependencies>
<!--web启动jar-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
```
#### 2.创建实体类
```
package tech.haonan.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Student {
private long id;
private String name;
private int age;
}
```
#### 3.创建studentRepository 接口和其实现类StudentRepositoryImpl
接口 studentRepository
```java
package tech.haonan.repository;
import tech.haonan.entity.Student;
import java.util.Collection;
public interface StudentRepository {
public Collection<Student> findAll();
public Student findById(long id);
public void saveOrUpdate(Student student);
public void deleteById(long id);
}
```
实现类 StudentRepositoryImpl
```java
package tech.haonan.repository.Impl;
import org.springframework.stereotype.Repository;
import tech.haonan.entity.Student;
import tech.haonan.repository.StudentRepository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@Repository
public class StudentRepositoryImpl implements StudentRepository {
private static Map<Long,Student> studentMap;
static {
studentMap = new HashMap<>();
studentMap.put(1L,new Student(1L,"张三",23));
studentMap.put(2L,new Student(2L,"李四",56));
studentMap.put(3L,new Student(3L,"王五",78));
}
@Override
public Collection<Student> findAll() {
return studentMap.values();
}
@Override
public Student findById(long id) {
return studentMap.get(id);
}
@Override
public void saveOrUpdate(Student student) {
studentMap.put(student.getId(),student);
}
@Override
public void deleteById(long id) {
studentMap.remove(id);
}
}
```
#### 4.创建StudentHandler
```java
package tech.haonan.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import tech.haonan.entity.Student;
import tech.haonan.repository.StudentRepository;
import java.util.Collection;
@RestController
@RequestMapping("/student")
public class StudentHandler {
@Autowired
private StudentRepository studentRepository;
@GetMapping("/findAll")
public Collection<Student> findAll(){
return studentRepository.findAll();
}
@GetMapping("/findById/{id}")
public Student findById(@PathVariable("id") long id){
return studentRepository.findById(id);
}
@PostMapping("/save")
public void save(@RequestBody Student student){
studentRepository.saveOrUpdate(student);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
studentRepository.saveOrUpdate(student);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") long id ){
studentRepository.deleteById(id);
}
}
```
#### 5.创建一个启动类 Application
application类的位置必须在需要托管的类的上层目录 否则就不能扫描了
```java
package tech.haonan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
```
#### 6.直接执行Application的main函数
### springboot的配置更改
在resource目录里新建`application.yml`
1. 端口修改为8000
```
server:
port: 8000
```
### springboot的静态目录
#### 默认目录
默认有四个路径是静态目录
1. src/main/resources/static 文件夹
2. src/main/resources/resources文件夹
3. src/main/resources/public文件夹
4. src/main/resources/META-INF/resources文件夹
优先级是 4 2 1 3
#### 更改默认目录
###### 编写配置类
```java
@Configuration
public class MyWebStaticResourcesConfg implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//* 表示匹配一个文件 ** 代表匹配所有文件和其子文件
registry.addResourceHandler("/test/**").addResourceLocations("classpath:/mystatic/");
}//这段代码的意思是 将访问localhost:端口/test的请求转发到 resource目录下的mystatic文件夹去寻找
}
```
它的优先级要高于前边四个
###### 修改properties
> spring.resources.static-locations=classpath:/mystatic/,classpath:/static
说明 : 谁在前面谁的优先级高
#### 默认的四个目录源码
源码中其实就是用了上边`编写配置类`的方法
ResourceProperties 类中规定了
> private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
### springBoot和AOP的整合
#### 目录结构
```shell
./
├── aaa.iml
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── tech
│ │ │ └── haonan
│ │ │ └── aaa
│ │ │ ├── AaaApplication.java
│ │ │ ├── aspect
│ │ │ │ └── ManAspect.java
│ │ │ └── entity
│ │ │ └── Man.java
│ │ └── resources
│ │ ├── application.properties
│ │ ├── static
│ │ └── templates
│ └── test
│ └── java
│ └── tech
│ └── haonan
│ └── aaa
│ └── AaaApplicationTests.java
```
#### pom.xml 引入aop依赖
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
```
#### 创建实体类 Man
```java
@Component
public class Man {
public String sleep(String str){
System.out.println("睡觉");
return "sleep";
}
}
```
#### 创建切面类
```java
@Aspect
@Component
public class ManAspect2 {
//声明切面
public static final String POINTCUT1 = "execution(* tech.haonan.aaa.entity.Man.sleep(..))";
// @Before(POINTCUT1)
public void before(){
System.out.println("睡前牛奶");
}
// @After(POINTCUT1)
public void after(){
System.out.println("起床了!!!!");
}
//把after和before集中到一块
@Around(POINTCUT1) //如果原函数是有返回值的 必须将值重新返回一下 否则会丢失返回值
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object[] args = proceedingJoinPoint.getArgs();//获取参数列表 可能有多个 这里只有一个 从0开始
before();
Object obj =proceedingJoinPoint.proceed();
after();
return obj;
}
//如果有异常之后打印相关信息
@AfterThrowing(value = POINTCUT1,throwing = "tw")
public void throwing(Throwable tw){
System.out.println("出现异常" + tw.getMessage());
}
}
```
#### 测试
```java
@SpringBootTest
class AaaApplicationTests {
@Autowired
Man man;
@Test
void contextLoads() {
String str=man.sleep("aaa");
System.out.println(str); //输出
/*
睡前牛奶
睡觉
起床了!!!!
sleep
*/
}
}
```
### springboot 管理SpringMVC的组件
#### 概述
使用spring MVC时需要配置的东西
1.前端控制器 2.控制映射器(`Map<Set<String>,Object>`)和适配器 3.视图解析器 4. 文件上传 5. 拦截器
#### 前端控制器的自动管理
源码在 WebMvcAutoConfiguration类中
#### 视图解析器
`ContentNegotiatingViewResolver`是一个视图解析器的收集器,`viewresolver`接口的继承类都会收集起来 如ThymeleafViewResolver
#### 文件上传
`MultipartAutoConfiguration`
#### 消息转换(string 转各种类型 前台向后台)
WebMvcAutoConfiguration 的 addFormatters的addBeans方法 可以提供各种类型的转换器 比如 string -> double
#### 在容器中注册视图控制器
templates文件夹中建立hello.html 注意得需要thymeleaf模板引擎 否则templates文件进不去
controller 可以实现视图的展现
```java
@Controller
@RequestMapping("hello")
public class HelloController {
@RequestMapping("index")
public String hello(){
return "hello";
}
}
```
有方法可以替代上述代码 不过必须是`不带参数的静态资源访问`
```java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//index/hello ---> IndexController ---> templates/hello.html
// registry.addRedirectViewController() 重定向
registry.addViewController("/hello/index")//请求转发
.setViewName("hello");
}
}
```
#### 注册格式化器
针对时间格式的功能
##### 以前的处理手段
1.
```java
public class Order {
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date orderTime; //这里ordertime 格式就是 1900-10-25 05:30:30
}
```
2.
```java
@RestController
@RequestMapping("hello")
public class HelloController {
@RequestMapping("addUser")
public String addUser(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date){
//http://localhost:8080/hello/addUser?date=2019-10-5 2019-10-5这种格式能访问
return date.toString();
}
}
```
##### 现在的处理手段
在application.properties文件中加上
> spring.mvc.date-format=yyyy--MM--dd
date=2019--10--5 格式为yyyy--MM--dd 的就都能访问了
##### 优先级问题
如果两种方法同时生效 那么`@DateTimeFormat `优先级更高
#### 自定义格式化器
```java
@Configuration//必须要重写 print 和 parse方法
//访问 http://localhost:8080/hello/addUser?date=19*05*20 是可以成功访问的
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new Formatter<Date>() {
@Override
public String print(Date date, Locale locale) {
return null;
}
@Override
public Date parse(String s, Locale locale) throws ParseException {//s 代表前台传进来的字符串
//创建自己的date转换器
SimpleDateFormat sdf = new SimpleDateFormat("yy*MM*dd");
return sdf.parse(s);
}
});
}
}
```
#### 消息转换器扩展fastjson (后台向前台转换)
##### 之前的处理方式
实体类User的创建 应用 `@JsonProperty` 和 `@Jsonformat`来进行消息转换
```java
public class User {
@JsonProperty(value = "userid") //这里将id和userid做了一个映射 返回json数据的时候就是userid
private Integer id;
private String name;
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")//返回日期的格式就是yyyy-MM-dd
private Date birth;
// {"name":"小明","birth":"2020-05-02","userid":1}
}
```
controller 层
```java
@RestController
@RequestMapping("hello")
public class HelloController {
@RequestMapping("getUser")
public User addUser(Date date){
return new User(1,"小明",new Date());
//页面显示 {"name":"小明","birth":"2020-05-02","userid":1}
}
}
```
##### 可以替代的另一种做法
pom.xml 引入fastjson的依赖
```xml
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
```
添加一个类 内容如下
```java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
//自定义扩展消息转化器 (平时是不会配置的 , 因为有jackson的转换器)
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter fc = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(SerializerFeature.PrettyFormat);
fc.setFastJsonConfig(config);
converters.add(fc);
}
}
```
这个时候会把原来User里的`@JsonProperty` 和 `@JsonFormat ` 给覆盖 输出结果是
```shell
{ "birth":1588399449317, "id":1, "name":"灏忔槑" }
```
这时候需要修改 User类
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
// @JsonProperty(value = "userid")
@JSONField(name = "userid")
private Integer id;
private String name;
// @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
@JSONField(format = "yyyy*MM*dd")
private Date birth;
}
// 会输出{ "birth":"2020*05*02", "name":"灏忔槑", "userid":1 }
```
#### 拦截器
##### 创建拦截器对象 MyInteceptor
```java
public class MyInteceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;//默认放行了
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
```
##### 注册拦截器
```java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override //重写addInterceptors 方法
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInteceptor())
.addPathPatterns("/**") //拦截一切
.excludePathPatterns("/hello/getUser"); //放行http://localhost:8080/hello/getUser
}
}
```
访问 http://localhost:8080/hello/index 就会打印
```shell
preHandle
postHandle
afterCompletion
```
### spring boot 使用jetty
#### 排除tomcat依赖 引入jetty
```xml
<!--排除默认的tomcat-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--启用jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
```
#### 直接启动就可以
如果启动不了 说明springboot的版本低 需要加入jetty的配置类
```java
@Configuration
public class ServerConfig{
@Bean
public ConfigurableServletWebServerFactory webServerFactory(){
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
return factory
}
}
```
### spring与jsp的整合
#### 0.目录结构
```shell
./
├── jspSpringboot.iml
├── pom.xml
└── src
└── main
├── java
│ └── tech
│ └── haonan
│ ├── Application.java
│ ├── controller
│ │ └── HelloHandler.java
│ ├── entity
│ │ └── Student.java
│ └── repository
│ ├── Impl
│ │ └── StudentRepositoryImpl.java
│ └── StudentRepository.java
├── resources
│ └── application.yml
└── webapp
├── index.jsp
├── save.jsp
├── update.jsp
└── WEB-INF
└── web.xml
12 directories, 12 files
```
#### 1.pom.xml依赖的处理
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>tech.haonan</groupId>
<artifactId>jspSpring</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>jspSpring Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!--web启动jar-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!--整合jsp-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<finalName>jspSpring</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
```
#### 2.resouces目录下的application.yml 文件的配置
配置文件更改了启动端口和识别jsp文件
```
server:
port: 8080
spring:
mvc:
view:
prefix: /
suffix: .jsp
```
#### 3.创建Handler
```java
package tech.haonan.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import tech.haonan.entity.Student;
import tech.haonan.repository.StudentRepository;
@Controller
@RequestMapping("/hello")
public class HelloHandler {
@Autowired
private StudentRepository studentRepository;
@RequestMapping("/index")
public ModelAndView hello(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index");
modelAndView.addObject("list",studentRepository.findAll());
return modelAndView;
}
@GetMapping("/findById/{id}")
public ModelAndView findById(@PathVariable("id") long id){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("update");
modelAndView.addObject("student",studentRepository.findById(id));
return modelAndView;
}
@PostMapping("/save")
public String save(Student student){
studentRepository.saveOrUpdate(student);
return "redirect:/hello/index";
}
@PostMapping("/update")
public String update(Student student){
studentRepository.saveOrUpdate(student);
return "redirect:/hello/index";
}
@GetMapping("/deleteById/{id}")
public String deleteById(@PathVariable("id") long id ){
studentRepository.deleteById(id);
return "redirect:/hello/index";
}
}
```
#### 4.jsp文件
```jsp
<%--
Created by IntelliJ IDEA.
User: yhn
Date: 2020/4/27
Time: 下午5:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>index</title>
</head>
<body>
<h1>学生信息</h1>
<table>
<tr>
<th>学生编号</th>
<th>学生姓名</th>
<th>学生年龄</th>
<th>操作</th>
</tr>
<c:forEach items="${list}" var="student">
<tr>
<td>${student.id}</td>
<td>${student.name}</td>
<td>${student.age}</td>
<td>
<a href="/hello/findById/${student.id}">修改</a>
<a href="/hello/deleteById/${student.id}">删除</a>
</td>
</tr>
</c:forEach>
</table>
<a href="/save.jsp">添加学生</a>
</body>
</html>
```
```jsp
<%--
Created by IntelliJ IDEA.
User: yhn
Date: 2020/4/27
Time: 下午5:50
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>save</title>
</head>
<body>
<form action="/hello/save" method="post">
id: <input type="text" name="id"> <br>
姓名: <input type="text" name="name"><br>
年龄 <input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
```
```jsp
<%--
Created by IntelliJ IDEA.
User: yhn
Date: 2020/4/27
Time: 下午5:50
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>update</title>
</head>
<body>
<form action="/hello/update" method="post">
id: <input type="text" name="id" value="${student.id}" readonly> <br>
姓名: <input type="text" name="name" value="${student.name} "><br>
年龄 <input type="text" name="age" value="${student.age}" ><br>
<input type="submit" value="提交">
</form>
</body>
</html>
```
#### 5.启动项目
```java
package tech.haonan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
```
### springboot和Thymeleaf的整合
#### 使用springboot Initializr创建springboot项目
勾选1.lombok 2.springboot developtools 3.springboot configuration processor 4. Thymeleaf
剩下的方式和下边一样
### spring和Thymeleaf的整合 麻烦的方式
Thymeleaf是一个模板 , 使用原生的HTML作为视图
Thymeleaf模板是面向Web和独立环境的Java模板引擎,能够处理HTML,XML,javaScript,css等
`这个工程直接使用第一个springboot快速启动的代码 不在重复 `
#### 0.目录结构
```shell
springboot/
├── pom.xml
├── springboot.iml
└── src
├── main
│ ├── java
│ │ └── tech
│ │ └── haonan
│ │ ├── Application.java
│ │ ├── controller
│ │ │ ├── IndexHandler.java
│ │ │ └── StudentHandler.java
│ │ ├── entity
│ │ │ └── Student.java
│ │ └── repository
│ │ ├── Impl
│ │ │ └── StudentRepositoryImpl.java
│ │ └── StudentRepository.java
│ └── resources
│ ├── application.yml
│ ├── static
│ │ └── test.html
│ └── templates
│ └── index.html
└── test
└── java
```
#### 1.添加thymeleaf依赖
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
```
#### 2.application.yml 配置
```yaml
server:
port: 8000
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
mode: HTML5
encoding: UTF-8
```
#### 3.新建一个IndexHandler
```java
package tech.haonan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import tech.haonan.entity.Student;
import java.util.ArrayList;
import java.util.List;
@Controller
@RequestMapping("/index")
public class IndexHandler {
@GetMapping("/aaa")
public String aaa(Model model){
List<Student> list = new ArrayList<>();
list.add(new Student(1L,"王五",15));
list.add(new Student(2L,"李四",26));
list.add(new Student(3L,"张三",66));
model.addAttribute("list",list);
return "index";
}
}
```
#### 4.通过接口访问html
html的内容
```html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1>啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊</h1>
<table>
<tr>
<th>学生id</th>
<th>学生姓名</th>
<th>学生年龄</th>
</tr>
<tr th:each="student:${list}">
<td th:text="${student.id}"></td>
<td th:text="${student.name}"></td>
<td th:text="${student.age}"></td>
</tr>
</table>
</body>
</html>
```
#### 5.直接访问html
上述操作只能通过访问`localhost:8000/index/aaa`来访问,如果想要直接访问需要在resource目录下创建static文件夹然后放入你想访问的html文件 详细内容在静态目录已经介绍过了
### springboot数据校验
添加一个实体类User
user类中使用注解来进行数据校验 以下是一个例子
```java
package tech.haonan.entity;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Data
public class User {
@NotNull(message = "id不能为空")
private Long id;
@NotEmpty(message = "姓名不能为空")
@Length(min = 2,message = "姓名长度不能小于2位")
private String name;
@Min(value = 16,message = "年龄必须大于16")
private int age;
}
```
如果需要数据校验 在传入数据时应该使用注解`@Valid`
Handler内容
```java
package tech.haonan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import tech.haonan.entity.User;
import javax.validation.Valid;
import java.util.List;
@Controller
@RequestMapping("/index")
public class IndexHandler {
/*直接访问 localhost:8000/index/validator
控制台会打印
User(id=null, name=null, age=0)
NotEmpty-姓名不能为空
NotNull-id不能为空
Min-年龄必须大于16
* */
@GetMapping("/validator")
public void ValidatorUser(@Valid User user, BindingResult bindingResult){
System.out.println(user);
if(bindingResult.hasErrors()){
List<ObjectError> list = bindingResult.getAllErrors();
for(ObjectError objectError:list){
System.out.println(objectError.getCode()+"-"+objectError.getDefaultMessage());
}
}
}
}
```
### SpringBootJDBC的整合
#### 0.目录结构
```shell
./
├── pom.xml
├── springboot.iml
└── src
├── main
│ ├── java
│ │ └── tech
│ │ └── haonan
│ │ ├── Application.java
│ │ ├── controller
│ │ │ └── UserHandler.java
│ │ ├── entity
│ │ │ └── User.java
│ │ └── repository
│ │ ├── Impl
│ │ │ └── UserRepositoryImpl.java
│ │ └── UserRepository.java
│ └── resources
│ └── application.yml
└── test
└── java
12 directories, 8 files
```
#### 1.pom.xml导入
```xml
<!--Springboot JDBC-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
```
#### 2.Application.yml 文件的配置
```shell
server:
port: 8000
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
mode: HTML5
encoding: UTF-8
datasource:
url: jdbc:mysql://localhost:4000/mybatis?useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
```
#### 3.实体类的书写
```java
package tech.haonan.entity;
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
@Data
public class User {
private long id;
@NotEmpty(message = "username不能为空")
private String username;
@NotEmpty(message = "password不能为空")
private String password;
@Min(value = 16,message = "年龄必须大于16")
private int age;
}
```
#### 4.UserRepository接口和UserRepositoryImpl实现类的书写
UserRepository
```java
package tech.haonan.repository;
import tech.haonan.entity.User;
import java.util.List;
public interface UserRepository {
public List<User> findAll();
public User findById(long id);
public void save(User user);
public void update(User user);
public void deleteById(long id);
}
```
UserRepositoryImpl
```java
package tech.haonan.repository.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import tech.haonan.entity.User;
import tech.haonan.repository.UserRepository;
import java.util.List;
@Repository
public class UserRepositoryImpl implements UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public List<User> findAll() {
return jdbcTemplate.query("select * from t_account", new BeanPropertyRowMapper<>(User.class));
}
@Override
public User findById(long id) {
//这里必须需要一个数组 因为参数可能是多个
Object[] array = new Object[]{id};
return jdbcTemplate.queryForObject("select * from t_account where id = ?",array,new BeanPropertyRowMapper<>(User.class));
}
@Override
public void save(User user) {
Object[] array = new Object[]{user.getUsername(),user.getPassword(),user.getAge()};
jdbcTemplate.update("insert into t_account(username,password,age) values(?,?,?)",array);
}
@Override
public void update(User user) {
Object[] array = new Object[]{user.getUsername(),user.getPassword(),user.getAge(),user.getId()};
jdbcTemplate.update("update t_account set username = ?,password = ?,age = ? where id =?",array);
}
@Override
public void deleteById(long id) {
Object[] array = new Object[]{id};
jdbcTemplate.update("delete from t_account where id = ?",array);
}
}
```
#### 5.UserHandler的使用
```java
package tech.haonan.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import tech.haonan.entity.User;
import tech.haonan.repository.UserRepository;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserHandler {
@Autowired
private UserRepository userRepository;
@GetMapping("/findAll")
public List<User> findAll(){
return userRepository.findAll();
}
@GetMapping("/findById/{id}")
public User findById(@PathVariable("id") long id){
return userRepository.findById(id);
}
@PostMapping("/save")
public void save(@RequestBody User user){
userRepository.save(user);
}
@PutMapping("/update")
public void update(@RequestBody User user){
userRepository.update(user);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById (@PathVariable("id") long id){
userRepository.deleteById(id);
}
}
```
### springboot和Mybatis的整合
#### 准备工作
##### 目录结构
这个目录结构包括了纯注解和xml两个方法所用到的文件
```shell
./
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
├── springbootmybatis.iml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── tech
│ │ │ └── haonan
│ │ │ ├── entity
│ │ │ │ └── Student.java
│ │ │ ├── mapper
│ │ │ │ ├── StudentMapper.java
│ │ │ │ └── StudentMapperxml.java
│ │ │ └── SpringbootmybatisApplication.java
│ │ └── resources
│ │ ├── application.yml
│ │ ├── mapper
│ │ │ └── StudentMapper.xml
│ │ ├── static
│ │ └── templates
│ └── test
│ └── java
│ └── tech
│ └── haonan
│ └── SpringbootmybatisApplicationTests.java
```
##### spring Initializr 创建项目
勾选1.lombok 2.springboot developtools 3.springboot configuration processor 4.spring web 5. JDBC api 6.MybatisFramework
##### 引入druid
```xml
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
```
##### 配置数据源 application.yml
```yml
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:4000/user?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
username: root
password: 123456
druid:
max-active: 10
min-idle: 5
max-wait: 5000
initial-size: 5
validation-query: select 1
stat-view-servlet:
enabled: true
login-username: admin
login-password: admin
allow:
deny:
url-pattern: "/druid/*"
### mybatis 的配置 输出sql语句
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
```
##### 排除springboot自带的数据源
DataSourceAutoConfiguration
```java
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
```
#### 使用纯注解整合
##### 创建Student类
```java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
private Long id;
private String name;
}
```
##### 创建StudentMapper
```java
@Mapper
@Repository
public interface StudentMapper {
@Delete("delete from student where id = #{id}")
int deleteByPrimaryKey(@Param("id") Long id);
@Insert("insert into student(name) values(#{name})")
int insert(Student student);
@Select("select * from student where id = #{id}")
Student selectByPrimaryKey(@Param("id") Long id);
@Update("update student set name = #{name} where id = #{id}")
int updateByPrimaryKey(Student student);
@Select("select * from student")
List<Student> queryAllUser();
}
```
##### 修改yml
```yml
#添加以下内容
# mybatis 的配置 输出sql语句
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
```
##### 配置扫描
方式一 :在StudentMapper类上加@Mapper 注解 和 @Repository注解
方式二: 在启动类上使用MapperScan(basePackages = {"tech.haonan.mapper"})
两种方式选一种就行
##### 测试
```java
@SpringBootTest
class SpringbootmybatisApplicationTests {
@Autowired
private StudentMapper studentMapper;
@Test
void contextLoads() {
System.out.println(studentMapper.queryAllUser());
}
}
```
#### 使用Mapper+Mapper.xml
记得安装一下 Free Mybatis plugin idea 的插件
##### 在resources目录下创建mapper文件夹 然后创建StudentMapper.xml
内容如下
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tech.haonan.mapper.StudentMapperxml" >
<!--删除-->
<delete id="deleteByPrimaryKey" >
delete from student where id = #{id}
</delete>
<!--添加-->
<insert id="insert">
insert into student(name) values(#{name})
</insert>
<!--查询一个-->
<select id="selectByPrimaryKey" resultType="tech.haonan.entity.Student">
select * from student where id = #{id}
</select>
<!--修改-->
<update id="updateByPrimaryKey" >
update student set name = #{name} where id = #{id}
</update>
<!--全查询-->
<select id="queryAllUser" resultType="tech.haonan.entity.Student">
select * from student
</select>
</mapper>
```
##### 创建StudentMapperxml类 内容如下
````java
public interface StudentMapperxml {
int deleteByPrimaryKey(@Param("id") Long id);
int insert(Student student);
Student selectByPrimaryKey(@Param("id") Long id);
int updateByPrimaryKey(Student student);
List<Student> queryAllUser();
}
````
##### 修改yml文件
添加一下内容 目的是让spring知道xml文件在哪里 好用来注入bean
```yml
mybatis:
mapper-locations:
- classpath:mapper/*Mapper.xml
```
##### 测试类的修改
```java
@SpringBootTest
class SpringbootmybatisApplicationTests {
@Autowired
private StudentMapperxml studentMapperxml;
@Test
void contextLoads() {
System.out.println(studentMapperxml.queryAllUser());
}
}
```
##### 题外话
yml文件可以加上
```yml
mybatis:
type-aliases-package: tech.haonan.entity
```
这样xml文件就不用写很长的全类名 了 例如下边直接写Student就行了
```xml
<select id="selectByPrimaryKey" resultType="Student">
select * from student where id = #{id}
</select>
```
#### 使用mybatis.cfg.xml
##### 创建mybatis.cfg.xml
在resources下边建立 mybatis.cfg.xml 文件
然后加入一下内容
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--用来配置type-aliases-package 和上边原理一样 -->
<!-- <typeAliases>-->
<!-- <package name="tech.haonan.entity"/>-->
<!-- </typeAliases>-->
<mappers>
<mapper resource="mapper/StudentMapper.xml"></mapper>
</mappers>
</configuration>
```
##### 配置yml文件
删掉以前的mybatis配置 加上这句话 意思是找到mybatis的配置文件 哪里有mapper的信息 其实就是套了个娃
```yml
mybatis:
config-location: classpath:mybatis.cfg.xml
```
#### 整合分页papeHelper
##### 修改pom.xml 引入pagehelper的依赖
```xml
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.11</version>
</dependency>
```
##### mybatis.cfg.xml 引入 分页的拦截器
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<mappers>
<mapper resource="mapper/StudentMapper.xml"></mapper>
</mappers>
</configuration>
```
##### 测试类
```java
@SpringBootTest
class SpringbootmybatisApplicationTests {
@Autowired
private StudentMapperxml studentMapperxml;
@Test
void page(){
Page<Object> page = PageHelper.startPage(1,2);
List<Student> students = studentMapperxml.queryAllUser();
System.out.println(page);
}
}
```
#### 整合分页pageHelper-starter
##### pom.xml 引入 pagehelper-spring-boot-starter
```xml
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.13</version>
</dependency>
```
##### 去掉mybatis.cfg.xml
##### 修改yml
```yml
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:4000/user?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
username: root
password: 123456
druid:
max-active: 10
min-idle: 5
max-wait: 5000
initial-size: 5
validation-query: select 1
stat-view-servlet:
enabled: true
login-username: admin
login-password: admin
allow:
deny:
url-pattern: "/druid/*"
mybatis:
mapper-locations: classpath:mapper/*.xml
pagehelper:
reasonable: true
support-methods-arguments: true
```
因为pagehelper-springboot-starter 有自动配置类 所以直接调用就行
分页的原理是拦截sql请求 拦截的是下一句有关sql的语句
```java
@SpringBootTest
class SpringbootmybatisApplicationTests {
@Autowired
private StudentMapperxml studentMapperxml;
@Test
void page(){
Page<Object> page = PageHelper.startPage(1,2);
List<Student> students = studentMapperxml.queryAllUser();
System.out.println(page);
}
}
```
springboot