Spring-Boot学习笔记
Spring Boot学习笔记
Maven创建Spring Boot的方法
在某些情况下,start.spring.io无法访问时,可以直接使用Maven创建Spring Boot项目
新建Maven项目
在pom.xml文件中添加
parent
节点1
2
3
4
5<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
</parent>添加
spring-boot-starter-web
和spring-boot-starter-test
依赖添加
spring-boot-maven-plugin
插件创建启动类
1
2
3
4
5
6
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
HttpMessageConverter
在Spring MVC中自动配置了Jackson
和Gson
的HttpMessageConverter
- 将服务端返回的对象序列化成
JSON
字符串 - 将前端传递的
JSON
字符串反序列化成Java
对象
自定义HttpMessageConverter
的方式
- Jackson
提供
MappingJackson2HttpMessageConverter
的bean
1
2
3
4
5
6
7
8
9
10
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new
MappingJackson2HttpMessageConverter();
ObjectMapper om = new ObjectMapper();
om.setDateFormat(new SimpleDateFormat("yyyy/MM/dd hh:mm:SSS"));
converter.setObjectMapper(om);
return converter;
}
//起主要作用的是ObjectMapper提供
ObjectMapper
1
2
3
4
5
6
ObjectMapper objectMapper() {
ObjectMapper om = new ObjectMapper();
om.setDateFormat(new SimpleDateFormat("yyyy/MM/dd hh/mm/SSS"));
return om;
}
- Gson
修改
spring-boot-starter-web
中默认的Jackson
依赖,添加Gson
依赖1
2
3
4
5
6
7
8
9
10
11
12
13
14<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>提供
GsonHttpMessageConverter
的bean
1
2
3
4
5
6
7
8
GsonHttpMessageConverter gsonHttpMessageConverter(){
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
converter.setGson(new
GsonBuilder().setDateFormat("yyyy/MM/dd").create());
return converter;
}
//起主要作用的是Gson提供
Gson
1
2
3
4
Gson gson(){
return new GsonBuilder().setDateFormat("yyyy/MM/dd").create();
}
- FastJson
修改
spring-boot-starter-web
中默认的Jackson
依赖,添加Fastjson
依赖1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>提供
FastJsonHttpMessageConverter
1
2
3
4
5
6
7
8
9
FastJsonHttpMessageConverter fastJsonHttpMessageConverter(){
FastJsonHttpMessageConverter converter = new
FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setDateFormat("yyyy/MM/dd");
converter.setFastJsonConfig(fastJsonConfig);
return converter;
}
静态资源的访问
在Spring Boot的WebMvcAutoConfiguration
中已经默认设置了五个静态资源的访问路径,按优先级顺序依次为META-INF/resources
、resources
、static
、public
、/
。
自定义静态资源的位置
在
application.properties
中添加1
2
3spring.resources.static-locations=classpath:/xxx/
# 也可以添加规则
spring.mvc.static-path-pattern=/**在
Java
类中配置1
2
3
4
5
6
7
public class WebMVCConfig implements WebMvcConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/xxx/");
}
}
文件上传
主要使用MultipartFile
类
创建
Controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class FileUploadController {
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
public String upload(MultipartFile file, HttpServletRequest req) {
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img") + format;
File folder = new File(realPath);
if (!folder.exists()) {
folder.mkdirs();
}
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
file.transferTo(new File(realPath, newName));
String url = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + "/img" + format + newName;
return url;
} catch (IOException e) {
e.printStackTrace();
}
return "error";
}
}创建
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="submit">
</form>
</body>
</html>关于上传文件大小的限制需要在
application.properties
中进行修改1
1MB =
@ControllerAdvice
全局异常处理
创建
MyCustomException
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MyCustomException {
//以response的方式返回
public void myException(MaxUploadSizeExceededException e, HttpServletResponse res) throws IOException {
res.setContentType("text/html;charset=utf-8");
PrintWriter out = res.getWriter();
out.write("上传文件大小超出限制!");
out.flush();
out.close();
}
//以视图的方式返回
public ModelAndView myException(MaxUploadSizeExceededException e) throws IOException {
ModelAndView modelAndView = new ModelAndView("myerror");
modelAndView.addObject("error", "文件大小超过限制!");
return modelAndView;
}
}以
ModelAndView
的方式返回需要创建错误页面myerror.html
以及thymeleaf
的依赖1
2
3
4
5
6
7
8
9
<head xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${error}"></h1>
</body>
</html>
预设全局数据
创建全局数据类,使用
Map
保存数据1
2
3
4
5
6
7
8
9
10
public class GlobalData {
public Map<String,Object> mydata(){
Map<String,Object> map = new HashMap<>();
map.put("name","wan");
map.put("gender","male");
return map;
}
}在
Controller
中使用Model
调用数据1
2
3
4
5
6
7
8
9
10
11
12
public class HelloController {
public String hello(Model model){
Map<String, Object> map = model.asMap();
Set<String> keySet = map.keySet();
for (String s : keySet) {
System.out.println(s+":"+map.get(s));
}
return "hello";
}
}
请求参数预处理
现在出现如下需求,前端向后端发送请求参数时出现命名冲突:
key | value |
---|---|
name | 三国演义 |
price | 99 |
name | 吴冠中 |
age | 100 |
此时在服务器端接受的数据会有问题,解决方法如下:
给接收参数重命名
1
2
3
4
5
6
7
8
public class BookController {
public void addBook( Book book, Author author){
System.out.println(book);
System.out.println(author);
}
}创建@ControllerAdvice类
1
2
3
4
5
6
7
8
9
public void initA(WebDataBinder binder){
binder.setFieldDefaultPrefix("a.");
}
public void initB(WebDataBinder binder){
binder.setFieldDefaultPrefix("b.");
}
@ModelAttribute
WebDataBinder
@InitBinder
ControllerAdvice
Model
ModelAndView
@ExceptionHandler
自定义异常
在
classpath
下的static
和template
目录中创建error
目录并创建静态错误页面和动态错误页面,按优先级依次访问:精确大于模糊,动态大于静态自定义错误数据
1
2
3
4
5
6
7
8
9
public class MyErrorConfig extends DefaultErrorAttributes {
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options);
errorAttributes.put("myerror","自定义异常信息!");
return errorAttributes;
}
}自定义错误视图
- 自定义
ErrorViewResolver
继承自DefaultErrorViewResolver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MyErrorViewResolver extends DefaultErrorViewResolver {
/**
* Create a new {@link DefaultErrorViewResolver} instance.
*
* @param applicationContext the source application context
* @param resourceProperties resource properties
*/
public MyErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties) {
super(applicationContext, resourceProperties);
}
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
ModelAndView modelAndView = super.resolveErrorView(request, status, model);
modelAndView.setViewName("myerror");
modelAndView.addObject(model);
return modelAndView;
}
}- 自定义视图
myerror.html
- 自定义
ErrorMvcAutoConfiguration
DefaultErrorAttributes
getErrorAttributes()
DefaultErrorViewResolver
resolveErrorView()
CORS解决跨域问题
在请求中添加注解
@CrosOrigin(origins = "http://xxxx:xxxx")
即可创建配置类
1
2
3
4
5
6
7
8
9
10
public class MyMVCConfig implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://xxxx:xxxx")
.allowedHeaders("*")
.allowedMethods("*");
}
}
WebMvcConfigurer
addCorsMappings(CorsRegistry registry)
XML
创建
beans.xml
1
2
3
4
5
6
7
<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 class="org.wan.xml.Hello" id="hello"/>
</beans>创建
MyWebNvcConfig
1
2
3
4
public class WebMvcConfig {
}
注册拦截器
自定义
Interceptor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}创建
WebMvcConfig
1
2
3
4
5
6
7
8
9
10
11
12
public class WebMvcConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor()).addPathPatterns("/**");
}
MyInterceptor myInterceptor(){
return new MyInterceptor();
}
}
定义系统启动任务
CommandLineRunner
创建MyCommanderLineRunner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MyCommandLineRunner1 implements CommandLineRunner {
public void run(String... args) throws Exception {
}
}
public class MyCommandLineRunner2 implements CommandLineRunner {
public void run(String... args) throws Exception {
}
}
//order表示优先级,值越小优先级越高
ApplicationRunner(获取参数的类型更丰富)
创建MyApplicationRunner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyApplicationRunner1 implements ApplicationRunner {
public void run(ApplicationArguments args) throws Exception {
}
}
public class MyApplicationRunner2 implements ApplicationRunner {
public void run(ApplicationArguments args) throws Exception {
}
}
CommandLineRunner
ApplicationRunner
类型转换器
需求:前端向后端传递日期的字符串,后端使用Date对象无法接收,此时需要自定义转换器
1 |
|
AOP
1 |
|
@Aspect
@Pointcut(“execution( org.wan.aop.service..*(..))”)
@Before(value = “pc1()”)
@After(value = “pc1()”)
@AfterReturning(value = “pc1()”,returning = “result”)
@Around(“pc1()”)
@AfterThrowing(value = “pc1()”,throwing = “e”)
JdbcTemplate
依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.16</version>
</dependency>
MySQL配置
1
2
3
4
5
6
7
8
9
10jdbc:mysql://localhost:3306/test1?characterEncoding=utf8&useSSL=true&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL =
root =
123456 =
com.alibaba.druid.pool.DruidDataSource =
jdbc:mysql://localhost:3306/test2?characterEncoding=utf8&useSSL=true&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL =
root =
123456 =
com.alibaba.druid.pool.DruidDataSource =自定义
DataSource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class DataSourceConfig {
DruidDataSource dsOne(){
return DruidDataSourceBuilder.create().build();
}
DruidDataSource dsTwo(){
return DruidDataSourceBuilder.create().build();
}
}自定义
JdbcTemplate
1
2
3
4
5
6
7
8
9
10
11
12
13
public class JdbcTemplateConfig {
JdbcTemplate jdbcTemplateOne( DataSource ds){
return new JdbcTemplate(ds);
}
JdbcTemplate jdbcTemplateTwo( DataSource ds){
return new JdbcTemplate(ds);
}
}
@ConfigurationProperties(prefix = “spring.datasource.one”)
DruidDataSource
DruidDataSourceBuilder.create().build()
JdbcTemplate
@Qualifier(“dsOne”) DataSource ds
MyBatis
添加依赖以及配置
resource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.16</version>
</dependency>
<!--添加resource的目的在于,将mapper.xml和对应的Mapper.java文件放在同一个package下-->
<!--也可以在resource目录下创建和对应Mapper.java相同路径的mapper.xml-->
<!--也可以将mapper.xml放于resource中的文件夹中,然后在application.properties中设置mybatis.mapper-locations=classpath:/mapper/*.xml-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
MySQL配置
1
2
3
4
5
6com.alibaba.druid.pool.DruidDataSource =
root =
123456 =
com.mysql.cj.jdbc.Driver =
jdbc:mysql://localhost:3306/test1?characterEncoding=utf8&useSSL=true&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL =
配置
mapper.xml
和mapper.java
1
2
3
4
5
6
7
<mapper namespace="com.example.mybatis.mapper.UserMapper">
<select id="getAllUser" resultType="com.example.mybatis.bean.User">
select * from user;
</select>
</mapper>1
2
3public interface UserMapper {
List<User> getAllUser();
}配置多数据源
配置数据源
1
2
3
4
5
6
7
8
9com.alibaba.druid.pool.DruidDataSource =
root =
123456 =
jdbc:mysql://localhost:3306/test1?characterEncoding=utf8&useSSL=true&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL =
com.alibaba.druid.pool.DruidDataSource =
root =
123456 =
jdbc:mysql://localhost:3306/test2?characterEncoding=utf8&useSSL=true&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL =创建
mapper1
和mapper2
两个package
,在各自包下创建mapper.xml
和mapper.java
创建自定义
DataSource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DataSourceConfig {
DataSource dataSourceOne(){
return DruidDataSourceBuilder.create().build();
}
DataSource dataSourceTwo(){
return DruidDataSourceBuilder.create().build();
}
}创建配置类
MyBatisConfigOne
和MyBatisConfigTwo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MyBatisConfigOne {
DataSource dsOne;
SqlSessionFactory sqlSessionFactory1(){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setDataSource(dsOne);
try {
return ssfb.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
SqlSessionTemplate sqlSessionTemplate1(){
return new SqlSessionTemplate(sqlSessionFactory1());
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MyBatisConfigTwo {
DataSource dsTwo;
SqlSessionFactory sqlSessionFactory2(){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setDataSource(dsTwo);
try {
return ssfb.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
SqlSessionTemplate sqlSessionTemplate2(){
return new SqlSessionTemplate(sqlSessionFactory2());
}
}
src/main/java **/*.xml src/main/resources @MapperScan(basePackages = “com.example.mybatis.mapper1”,sqlSessionFactoryRef = “sqlSessionFactory1”,
sqlSessionTemplateRef = “sqlSessionTemplate1”)SqlSessionFactory
SqlSessionTemplate
JPA
依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.16</version>
</dependency>MySQL配置
1
2
3
4
5
6
7
8
9
10
11
12com.alibaba.druid.pool.DruidDataSource =
jdbc:mysql://localhost:3306/test1?characterEncoding=utf8&useSSL=true&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL =
root =
123456 =
com.mysql.cj.jdbc.Driver =
true =
mysql =
mysql =
update =
org.hibernate.dialect.MySQL57Dialect =创建bean
1
2
3
4
5
6
7
8
public class Book {
private Integer id;
private String name;
private String author;
}创建dao
1
2public interface BookDao extends JpaRepository<Book,Integer> {
}
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.database-platform=mysql
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect@Entity(name = “t_book”)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)JpaRepository