SpringBoot
SpringBoot简介
原有Spring优缺点分析
Spring的优点分析
Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE)的轻量级代替品。无需开发重量级的Enterprise JavaBean(EJB),Spring为企业级Java开发提供了一种相对简单的方法,通过依赖注入和面向切面编程,用简单的Java对象(Plain Old Java Object,POJO)实现了EJB的功能。
Spring的缺点分析
虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。过多的XML文件配置。
所有这些配置都代表了开发时的损耗。因为在思考Spring特性配置和解决业务问题之间需要进行思维切换,所以编写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring实用,但与此同时它要求的回报也不少。
除此之外,项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。
SpringBoot的概述
SpringBoot解决上述Spring的缺点
SpringBoot对上述Spring的缺点进行的改善和优化,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度上缩短了项目周期。
特点
- 为基于Spring的开发提供更快的入门体验
- 开箱即用,没有代码生成,也无需XML配置。同时也可以修改默认值来满足特定的需求
- 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等
- SpringBoot不是对Spring功能上的增强,而是提供了一种快速使用Spring的方式
核心功能
- 起步依赖
起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依
赖,这些东西加在一起即支持某项功能。
简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。 - 自动配置
Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。
SpringBoot快速入门
快速入门
创建Maven工程
使用idea工具创建一个maven工程,该工程为普通的java工程即可。
添加SpringBoot的起步依赖
SpringBoot要求,项目要继承SpringBoot的起步依赖spring-boot-starter-parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
添加web启动器
SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
管理jdk版本
默认情况下,maven工程的jdk版本是1.5,而我们开发使用的是1.8,因此这里我们需要修改jdk版本,只需要简单的添加以下属性即可:
<properties>
<java.version>11</java.version>
</properties>
编写SpringBoot引导类
Spring Boot项目通过main函数即可启动,我们需要创建一个启动类,例如:
package com.sp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class,args);
}
}
注:
(1)@SpringBootApplication:标注SpringBoot的启动类
(2)SpringApplication.run(MySpringBootApplication.class) 代表运行SpringBoot的启动类,参数为SpringBoot启动类的字节码对象
编写Controller
在引导类MySpringBootApplication同级包或者子级包中创建xxxController,例如:
package com.sp.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "Hello SpringBoot";
}
}
启动测试
运行MySpringBootApplication主函数,启动Springboot,控制台查看信息。若端口冲突,则在配置文件中修改端口号,在重新启动。如:配置文件(application.properties)
server.port=端口号
如:server.port=8085
打开网页访问位置,如:localhost:8085/hello
SpringBoot工程热部署
我们在开发中反复修改类、页面等资源,每次修改后都是需要重新启动才生效,这样每次启动都很麻烦,浪费了大量的时间,我们可以在修改代码后不重启就能生效,在 pom.xml 中添加如下配置就可以实现这样的功能,我们称之为热部署。
<!--热部署配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
SpringBoot 基础配置
@SpringBootApplication
@SpringBootApplication 注解是加在项目的启动类上的。@SpringBootApplication 实际上是一个组合注解,定义如下:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
//代码略
}
-
第一个@SpringBootConfiguration 的定义如下:
@Configuration public @interface SpringBootConfiguration { }
原来就是一个@Configuration ,所以@Spring BootConfiguration 的功能就是表明这是一个配置
类,开发者可以在这个类中配置Bean。从这个角度来讲,这个类所扮演的角色有点类似于Spring
中applicationContext.xml 文件的角色。 -
第二个注解@EnableAutoConfiguration 表示开启自动化配置。Spring Boot 中的自动化配置是非侵入式的,在任意时刻,开发者都可以使用自定义配置代替自动化配置中的某一个配置。
-
第三个注解@ComponentScan 完成包扫描,也是Spring 中的功能。由于@ComponentScan 注解默认扫描的类都位于当前类所在包的下面, 因此建议在实际项目开发中把项目启动类放在根包中。
- 项目启动类中的@ComponentScan 注解,除了扫描@Service , @Repository 、@Component 、@Controller 和@RestController 等之外,也会扫描@Configuration 注解的类。
Web 容器配置
Tomcat 配置
-
常规配置
在Sprin g Boot 项目中,可以内置Tomcat 、Jetty 、Undertow 、Netty 等容器。当开发者添加了spring-boot-starter-web 依赖之后, 默认会使用Tomcat 作为Web 容器。如果需要对Tomcat 做进一步的配置,可以在application.properties 中进行配置,代码如下:
#配直了Web 容器的端口号 server.port=8080 #配直了当项目出错时跳转去的页面 server.error.path=/error #配直了session 失效时间, 30m表示30分钟,如果不写单位, 默认单位是秒。 server.servlet.session.timeout=30m #表示项目名称,不配直时,默认为/。如果配直了,就要在访问路径中加上配直的路径。 server.servlet.context-path=/chapter02 #表示配直Tomcat 请求编码。 server.tomcat.uri-encoding=utf-8 #表示Tomcat 最大线程数。 server.tomcat.max-threads=500 #存放Tomcat 运行日志和临时文件的目录,若不配直,则默认使用系统的临时目录。 server.tomcat.basedir=/home/sang/tmp
Properties 配置
Spring 提供了@Value 注解以及EnvironmentAware 接口来将Spring Environment中的数据注入到属性上, Spring Boot 对此进一步提出了类型安全配置属性( Type-safe ConfigurationProperties ) ,这样即使在数据量非常庞大的情况下,也可以更加方便地将配置文件中的数据注入Bean 中。
-
在application.properties进行配置,如:
book.name=水浒传 book.price=30.0 book.author=施耐庵
-
编写类,如:
@Component @ConfigurationProperties(prefix = "book") public class Book { private String name; private double price; private String author; //省略getter/setter
注:
- @ConfigurationProperties 中的prefix 属性描述了要加载的配置文件的前缀。
-
测试
YAML 配置
YAML 是JSON 的超集,简洁而强大,是一种专门用来书写配置文件的语言,可以替代application .properties 。在创建一个Spring Boot 项目时,引入的spring-boot-starter-web 依赖间接地引入了snakeyaml 依赖, snakeyaml 会实现对YAML 配置的解析。YAML 的使用非常简单,利用缩进来表示层级关系,并且大小写敏感。
YAML 不仅可以配置常规属性,也可以配置复杂属性, 例如下面一组配置:
book:
name:红楼梦
price:12.5
author:曹雪芹
feature:
生动
好看
便宜
@Component
@ConfigurationProperties(prefix = "book")
public class Book {
private String name;
private double price;
private String author;
private List<String> feature;
//省略getter/setter
Spring Boot 整合Web 开发
静态资源访问
默认策略
Spring Boot 默认会过滤所有的静态资源, 而静态资源的位置一共有5 个,分别是"classpath:/META-INF /resources/"、“classpath: /resources/”、“classpath: /static/”、“classpath :/public/“以及”/”,也就是说,开发者可以将静态资源放到这5 个位置中的任意一个。注意, 按照定义的顺序, 5 个静态资源位置的优先级依次降低。但是一般情况下, Spring Boot 项目不需要webapp 目录,所以第5 个"/"可以暂不考虑。
自定义策略
如果默认的静态资源过滤策略不能满足开发需求,也可以自定义静态资源过滤策略,
静态资源过滤策略有以下两种方式:
-
在自己置文件中定义
spring.mvc.static-path-pattern=/static/** spring.resources.static-locations=classpath:/static 注: (1)过滤规则为/static/**, 静态资源位置为classpath:/static/。 (2)重新启动项目, 在浏览器中输入"localhost:8080/static/pl.png ",即可看到classpath:/static/目录下的资源。
-
Java 编码定义
也可以通过Java 编码方式来定义,此时只需要实现WebMvcConfigurer 接口即可, 然后实现该接口的addResourceHandlers 方法,代码如下:
@Configuration public class MyWebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static"); } }
文件上传
-
首先创建一个Spring Boot 项目并添加spring-boot-starter-web 依赖。然后在resources 目录下的static 目录中创建一个upload.html 文件,内容如下:
<form action="/upload" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="fileName" value="请选择文件"> <input type="submit" value="提交"> </form>
-
创建上传控制器,如:
@PostMapping("/upload") @ResponseBody public String upload(MultipartFile fileName){ File file = new File("D://upload"); Random random = new Random(); if (!file.exists()){ file.mkdirs(); } String oldName = fileName.getOriginalFilename(); int ran = random.nextInt(900000)+100000; String newName = ran+oldName.substring(oldName.lastIndexOf("."),oldName.length()); try { fileName.transferTo(new File(file,newName)); return "上传成功"; } catch (IOException e) { e.printStackTrace(); } return "上传失败"; }
-
测试
-
配置文件上传大小
#配置文件上传大小 #是否开启文件上传支持,默认为true spring.servlet.multipart.enabled=true #文件写入磁盘的闽值,默认为0 spring.servlet.multipart.file-size-threshold=0 #上传文件的临时保存位直 spring.servlet.multipart.location=E:\\temp #上传的羊个文件的最大大小,默认为1MB spring.servlet.multipart.max-file-size=5MB #多文件上传时文件的总大小,默认为10MB spring.servlet.multipart.max-request-size=10MB #文件是否延迟解析,默认为false spring.servlet.multipart.resolve-lazily=false
@ControllerAdvice
顾名思义,@ControllerAdvice 就是@Controller 的增强版。@ControllerAdvice 主要用来处理全局数据, 一般搭配@ExceptionHandler、@ModelAttribute 以及@InitBinder 使用。
全局异常处理
@ControllerAdvice 最常见的使用场景就是全局异常处理。如果用户上传的文件超过了限制大小,就会抛出异常,此时可以通过@ControllerAdvice 结合@ExceptionHandler 定义全局异常捕获机制,代码如下:
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(MaxUploadSizeExceededException.class)
public void uploadException (MaxUploadSizeExceededException e, HttpServletResponse response) throws IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.write("上传文件大小超出限制!");
out.flush();
out.close();
}
}
只需在系统中定义CustomExceptionHandler 类,然后添加@Con位oilerAdvice 注解即可。当系统启动时,该类就会被扫描到Spring 容器中,然后定义uploadException 方法,在该方法上添加了@ExceptionHandler 注解,其中定义的MaxUploadS izeExceededException.class 表明该方法用来处理MaxUploadSizeExceededExcepti on 类型的异常。如果想让该方法处理所有类型的异常,只需将MaxUploadSizeExceededException 改为Exception 即可。
拦截器
Spring MVC 中提供了AOP 风格的拦截器,拥有更加精细的拦截处理能力。Spring Boot 中拦
截器的注册更加方便,如:
public class MyInterceptorl implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Myinterceptorl>>preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Myinterceptorl>>postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Myinterceptorl>>afterCompletion");
}
}
拦截器中的方法将按preHandle→ Controller → postHandle→ afterCompletion 的顺序执行。注意,只有preHandle 方法返回true 时后面的方法才会执行。当拦截器链内存在多个拦截器时, postHandler在拦截器链内的所有拦截器返回成功时才会调用,而afterCompletion 只有preHandle 返回true 才调用,但若拦截器链内的第一个拦截器的preHandle 方法返回false ,则后面的方法都不会执行。
配置拦截器。定义配置类进行拦截器的配置,代码如下:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptorl()).addPathPatterns("/**")
.excludePathPatterns("/hello");
}
}
注:
(1)自定义类实现WebMvcConfigurer接口,实现接口中的addlnterceptors。
(2)addPathPattems 表示拦截路径, excludePathPattems 表示排除的路径。
配置 AOP
Spring 框架对AOP 提供了很好的支持。在AOP 中,有一些常见的概念需要读者了解。
- Joinpoint (连接点):类里面可以被增强的方法即为连接点。例如,想修改哪个方法的功能,那么该方法就是一个连接点。
- Pointcut(切入点):对Joinpoint 进行拦截的定义即为切入点,例如,拦截所有以insert 开始的方法,这个定义即为切入点。
- Advice (通知):拦截到Joinpoint 之后所要做的事情就是通知。例如, 上文说到的打印日志监控。通知分为前直通知、后直通知、异常通知、最终通知和环绕通知。
- Aspect (切面): Pointcut 和Advice 的结合。
- Target (目标对象):要增强的类称为Target。
步骤
-
导入jar包
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
编写Service类,如:
public interface UserService { User findById(int id); void addUser(User user); } @Service public class UserServiceImpl implements UserService{ @Override public User findById(int id) { User user = new User(id,"张三","123456","云南省"); System.out.println(user); return user; } @Override public void addUser(User user) { System.out.println("添加成功"); System.out.println(user); } }
-
编写切面
@Component @Aspect public class UserAspect { @Pointcut("execution(* com.sp.service.*.*(..))") public void pct(){} @Before("pct()") public void before(JoinPoint jt){ String name = jt.getSignature().getName(); System.out.println(name+"方法开始"); } @After("pct()") public void after(JoinPoint jt){ String name = jt.getSignature().getName(); System.out.println(name+"方法开始"); } @AfterReturning(value = "pct()",returning = "result") public void afterReturning(JoinPoint jt,Object result){ String name = jt.getSignature().getName(); System.out.println(name+"方法返回值为: "+result); } @AfterThrowing(value = "pct()",throwing = "e") public void afterThrowing(JoinPoint jt,Exception e){ String name = jt.getSignature().getName(); System.out.println(name+"方法抛出了异常,异常是: "+e.getMessage()); } @Around("pct()") public Object around(ProceedingJoinPoint pj) throws Throwable { return pj.proceed(); } }
注:
- @Aspect 注解表明这是一个切面类。
- @Pointcut 注解,这是一个切入点定义,execution 中的第一个*表示方法返回任意值,第二个*表示service 包下的任意类,第三个*表示类中的任意方法,括号中的两个点表示方法参数任意,即这里描述的切入点为service 包下所有类中的所有方法。
- @Before 注解,表示这是一个前直通知,该方法在目标方法执行之前执行。通过JoinPoint参数可以获取目标方法的方法名、修饰符等信息。
- @After注解,表示这是一个后直通知,该方法在目标方法执行之后执行。
- @AfterReturning注解,表示这是一个返回通知,在该方法中可以获取目标方法的返回值。@AfterReturning 注解的returning 参数是指返回值的变量名,对应方法的参数。
- @AfterThrowing 注解, 表示这是一个异常通知, 即当目标方法发生异常时,该方法会被调用,异常类型为Exception 表示所有的异常都会进入该方法中执行, 若异常类型为ArithmeticException , 则表示只有目标方法抛出的ArithmeticException 异常才会进入该方法中处理。
- @Around 注解,表示这是一个环绕通知。环绕通知是所有通知
里功能最为强大的通知,可以实现前直通知、后直通知、异常通知以及返回通知的功能。
4.测试
SpringBoot 整合持久层技术
导入jar包
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
整合JdbcTemplate
-
配置数据库连接
#配置数据库 #数据库连接池 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource #数据库连接地址 spring.datasource.url=jdbc:mysql://localhost:3306/db8?characterEncoding=utf8&useSSL=false #用户名 spring.datasource.username=root #密码 spring.datasource.password=123456
-
创建实体类,例如:
@Data public class Book implements Serializable { private int id; private String name; private String author; private double price; private String sort; private String publish; private String publication; }
-
创建数据库访问层,例如:
public interface BookDao { List<Book> findAll(); void insert(Book book); } @Repository public class BookDaoImpl implements BookDao { public final static String SQL_FIND_ALL = "SELECT * FROM tb_book"; public final static String SQL_INSERT = "INSERT INTO tb_book(name,author,price,sort,publish,publication)" + "VALUES(?,?,?,?,?,?)"; @Autowired private JdbcTemplate jdbcTemplate; @Override public List<Book> findAll() { return jdbcTemplate.query(SQL_FIND_ALL,new BeanPropertyRowMapper<>(Book.class)); } @Override public void insert(Book book) { jdbcTemplate.update(SQL_INSERT,book.getName(),book.getAuthor(),book.getPrice(),book.getSort(),book.getPublish(),book.getPublication()); } }
-
测试,如:
@RunWith(SpringRunner.class) @SpringBootTest public class Demo01 { @Autowired private BookDao dao; @Test public void test01(){ List<Book> books = dao.findAll(); for (Book b: books) { System.out.println(b); } } }
整合MyBatis
-
添加jar包
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> <version>1.3.8.RELEASE</version> </dependency>
-
配置数据库
#配置数据库 #数据库连接池 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource #数据库连接地址 spring.datasource.url=jdbc:mysql://localhost:3306/db8?characterEncoding=utf8&useSSL=false #用户名 spring.datasource.username=root #密码 spring.datasource.password=123456 #配置Mybatis #别名 mybatis.type-aliases-package=com.sp.bean # mapper.xml文件位置,如果没有映射文件,请注释掉 mybatis.mapper-locations=classpath:mapper/*.xml #配置日志 mybatis.configuration.log-impl=org.apache.ibatis.logging.log4j.Log4jImpl
-
日志文件
log4j.rootLogger=ERROR, stdout log4j.logger.com.sp.dao=TRACE log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
-
编写实体类(上面已创建)
-
编写接口,如:
@Repository public interface BookMapper { List<Book> findAll(); } 注: (1)@Mapper 注解,表明该接口是一个MyBatis中的Mapper,这种方式需要在每一个Mapper 上都添加注解。 (2)在配直类上添加@MapperScan("mapper包名")注解,表示扫描mapper包下的所有接口作为Mapper,这样就不需要在每个接口上配直@Mapper注解了。
-
编写映射文件,例如:
<?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="com.sp.dao.BookMapper"> <resultMap id="bookMap" type="com.sp.bean.Book"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="author" column="author"/> <result property="price" column="price"/> <result property="sort" column="sort"/> <result property="publish" column="publish"/> <result property="publication" column="publication"/> </resultMap> <select id="findAll" resultMap="bookMap"> select * from tb_book </select> </mapper>
-
配置包扫描
@SpringBootApplication @MapperScan("com.sp.dao") public class MySpringBootApplication { public static void main(String[] args) { SpringApplication.run(MySpringBootApplication.class,args); } }
-
测试
通用mapper
通用mapper 可以极大的方便开发人员进行ORM,提供极其方便的单表增删改查。
什么是通用mapper,一句话简单说,它就是个辅助mybatis极简单表开发的组件。它不是为了替代mybatis,而是让mybatis的开发更方便。
-
导入jar包
<!-- https://mvnrepository.com/artifact/tk.mybatis/mapper-spring-boot-starter --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>2.1.5</version> </dependency>
-
使用,例如:
@Data @Table(name = "person") public class Person implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "t_id") private int id; @Column(name = "t_name") private String name; @Column(name = "age") private int age; @Column(name = "sex") private String sex; @Column(name = "address") private String address; @Column(name = "telephone") private String phone; }
注:
- 默认表名=类名,字段名=属性名
- 表名可以使用@Table(name = “tableName”) 进行指定
- @Column(name = “fieldName”) 指定
- 使用@Transient 注解表示跟字段不进行映射
-
接口处使用,例如:
@Repository public interface PersonMapper extends Mapper<Person> { @Override List<Person> selectAll(); }
-
后续配置同上
-
测试
SpringBoot 整合视图层技术
整合Thymeleaf
Thymeleaf 是新一代Java 模板引擎,类似于Velocity、FreeMarker 等传统Java 模板引擎。与传统Java 模板引擎不同的是, Thymeleaf 支持HTML 原型,既可以让前端工程师在浏览器中直接打开查看样式, 也可以让后端工程师结合真实数据查看显示效果。同时, Spring Boot 提供了Thymeleaf自动化配置解决方案,因此在Spring Boot 中使用Thymeleaf 非常方便。
步骤
-
安装jar包
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
-
配置Thymeleaf
#是否开启缓存,开发时可设置为false,默认为true spring.thymeleaf.cache=true #检查模板是否存在,默认为true spring.thymeleaf.check-template=true #检查模板位置是否存在,默认为true spring.thymeleaf.check-template-location=true #模板文件编码 spring.thymeleaf.encoding=utf-8 #模板文件位置 spring.thymeleaf.prefix=classpath:/templates/ #Content-Type配置 spring.thymeleaf.servlet.content-type=text/html #模板文件后缀 spring.thymeleaf.suffix=.html
-
配置控制器,例如:
@Controller @RequestMapping("/book") public class BookController { @Autowired private BookService bookService; @RequestMapping("/findAll") public ModelAndView findAll(){ List<Book> books = bookService.findAll(); ModelAndView mv = new ModelAndView(); mv.addObject("books",books); mv.setViewName("bookList"); return mv; } }
-
创建视图,例如:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>图书列表</title> <style> table{ text-align: center; } </style> </head> <body> <table border="1"> <tr> <th>编号</th> <th>书名</th> <th>作者</th> <th>价格</th> <th>类型</th> <th>出版社</th> <th>出版时间</th> </tr> <tr th:each="book:${books}"> <td th:text="${book.id}"></td> <td th:text="${book.name}"></td> <td th:text="${book.author}"></td> <td th:text="${book.price}"></td> <td th:text="${book.sort}"></td> <td th:text="${book.publish}"></td> <td th:text="${book.publication}"></td> </tr> </table> </body>
注:
(1)把html 的名称空间,改成: xmlns:th=“http://www.thymeleaf.org” 会有语法提示
(2)th- 指令: th- 是利用了Html5中的自定义属性来实现的。如果不支持H5,可以用data-th- 来代替。
(3)th:each :类似于c:foreach 遍历集合,但是语法更加简洁。
(4)th:text :声明标签中的文本
(5)${} :这个类似与el表达式,但其实是ognl的语法,比el表达式更加强大
-
测试
访问:http://localhost:8085/book/findAll 是否成功。
-
thymeleaf其他知识
表达式
-
变量表达式:变量表达式即OGNL表达式或Spring EL表达式(在Spring中用来获取model attribute的数据)。如下所示:
${session.user.name} 例如: <td th:text="${book.id}"></td>
-
选择(星号)表达式:选择表达式很像变量表达式,不过它们用一个预先选择的对象来代替上下文变量容器(map)来执行,如下:
*{customer.name} 被指定的object由th:object属性定义: <tr th:each="user : ${users}" th:object="${user}"> <td th:text="${user.id}">1</td> <td th:text="*{name}">张三</td> <td th:text="*{userName}">zhangsan</td> ...
-
URL表达式:URL表达式指的是把一个有用的上下文或回话信息添加到URL,这个过程经常被叫做URL重写。
(1)无参数返回:@{/order/list} (2)设置参数:@{/order/details(id=${orderId}, name=*{name})} (3)相对路径:@{../documents/report} (4)url表达式:<a th:href="@{/delete(id=${user.id}, userName=*{userName})}">删除</a>
常用th标签
(1)th:text:文本替换 <p th:text="${collect.description}">description</p > (2)th:id:替换id <input th:id="'xxx' + ${collect.id}"/ > (3)th:utext:支持html的文本替换 <p th:utext="${htmlcontent}">conten</p> (4)th:object 替换对象< div th:object="${session.user}"> (5)th:value 属性赋值 <input th:value="${user.name}" /> (6)th:with 变量赋值运算 <div th:with="isEven=${prodStat.count}%2==0">< /div> (7)th:style 设置样式 th:style="'display:' + @{(${sitrue} ? 'none' : 'inline-block')} + ''" (8)th:onclick 点击事件th:onclick="'getCollect()'" (9)th:each 属性赋值tr th:each="user,userStat:${users}"> (10)th:if 判断条件 <a th:if="${userId == collect.userId}" > (11)th:href 链接地 (12)th:switch 多路选择,配合th:case使用 < div th:switch="${user.role}"> (13)th:case th:switch的一个分支 <p th:case="'admin'">User is an administrator< /p> (14)th:action 表单提交的地址 <form action="subscribe.html" th:action="@{/subscribe}">
基本用法
-
赋值、字符串拼接
字符串拼接还有另外一种简洁的写法
<a th:href="|/update/${user.id}|">修改</a> <a th:href="'/approve/' + ${user.id}">审核</a>
-
条件判断 If/Unless
Thymeleaf中使用th:if和th:unless属性进行条件判断,下面的例子中, <a> 标签只有在th:if 中条件成立时才显 示: <h5>if指令</h5> <a th:if="${users.size() > 0}">查询结果存在</a><br> <a th:if="${users.size() <= 0}">查询结果不存在</a><br> <a th:unless="${session.user != null}" href="#">登录<a><br>
-
for 循环
<tr th:each="book:${books}"> <td th:text="${book.id}"></td> <td th:text="${book.name}"></td> <td th:text="${book.author}"></td> <td th:text="${book.price}"></td> <td th:text="${book.sort}"></td> <td th:text="${book.publish}"></td> <td th:text="${book.publication}"></td> </tr>
-
-
整合 FreeMarker
FreeMarker 是一个非常古老的模板引擎,可以用在Web 环境或者非Web 环境中。与Thymeleaf不同, FreeMarker 需要经过解析才能够在浏览器中展示出来。FreeMarker 不仅可以用来配置HTML页面模板,也可以作为电子邮件模板、配置文件模板以及源码模板等。
-
下载jar包
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-freemarker --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
-
配置FreeMarker
#HttpServletRequest 的属性是否可以覆盖controller中model的同名项 spring.freemarker.allow-request-override=false #HttpSession的属性是否可以覆盖controller中的model的同名项 spring.freemarker.allow-session-override=false #是否开启缓存 spring.freemarker.cache=false #模板文件编码 spring.freemarker.charset=utf-8 #是否检查模板位置 spring.freemarker.check-template-location=true #Content-Type的值 spring.freemarker.content-type=text/html #是否将HttpServletRequest 中的属性添加到Model中 spring.freemarker.expose-request-attributes=false #是否将HttpSession 中的属性添加到Model中 spring.freemarker.expose-session-attributes=false #模板文件后缀 spring.freemarker.suffix=.ftl #模板文件位置 spring.freemarker.template-loader-path=classpath:/templates/
-
创建控制器,同上
-
创建视图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>图书列表</title> <style> table{ text-align: center; } </style> </head> <body> <table border="1"> <tr> <th>编号</th> <th>书名</th> <th>作者</th> <th>价格</th> <th>类型</th> <th>出版社</th> <th>出版时间</th> </tr> <#if books ??&& (books?size>0)> <#list books as book> <tr> <td>${book.id}</td> <td>${book.name}</td> <td>${book.author}</td> <td>${book.price}</td> <td>${book.sort}</td> <td>${book.publish}</td> <td>${book.publication}</td> </tr> </#list> </#if> </table> </body>
-
测试,同上
Mybatis Plus插件使用
-
导入jar包
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.2</version> </dependency>
-
配置配置文件
#配置数据库 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource #配置数据库驱动 spring.datasource.driver-class-name=com.mysql.jdbc.Driver #请求地址 spring.datasource.url=jdbc:mysql://localhost:3306/db8?characterEncoding=utf8&useSSL=false #用户名 spring.datasource.username=root #密码 spring.datasource.password=123456 #配置mybatis plus #定义别名包 将实体对象的包路径进行封装. #mybatis-plus.type-aliases-package=com.sp.pojo #mybatis-plus.mapper-locations=classpath:mapper/*.xml mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.log4j.Log4jImpl
-
编写实体类
-
编写mapper映射接口,如:
@Repository public interface BookMapper extends BaseMapper<Book> { }
-
测试,如:
@RunWith(SpringRunner.class) @SpringBootTest public class BookTest { @Autowired private BookMapper bookMapper; @Test public void test01(){ List<Book> books = bookMapper.selectList(null); } }
常用注解
MyBatisPlus提供了一些注解供我们在实体类和表信息出现不对应的时候使用。通过使用注解完成逻辑上匹配。
@TableName :实体类的类名和数据库表名不一致
@TableId :实体类的主键名称和表中主键名称不一致
@TableField :实体类中的成员名称和表中字段名称不一致
如果mysql自增主键注解策略设置如下:@TableId(type = IdType.AUTO)
分页
内置分页
-
添加内容
@Configuration public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor().setCountSqlParser(new JsqlParserCountOptimize(true)); } }
-
使用MybatisPlus内置分页测试,如:
@Test public void test06(){ Page<Book> page = new Page<>(1,3); IPage<Book> bookPage = bookMapper.selectPage(page,new QueryWrapper<>()); List<Book> books = bookPage.getRecords(); System.out.println("总条数: " + bookPage.getTotal()); System.out.println("当前页数: " + bookPage.getCurrent()); System.out.println("当前每页显示数: " + bookPage.getSize()); System.out.println("总页数: "+bookPage.getPages()); }
自定义xml分页
-
在配置中文件中添加以下信息:
配置mybatis plus #定义别名包 将实体对象的包路径进行封装. mybatis-plus.type-aliases-package=com.sp.pojo mybatis-plus.mapper-locations=classpath:mapper/*.xml
-
编写映射接口,例如:
@Repository public interface BookMapper extends BaseMapper<Book> { public IPage<Book> findByPage(@Param("p")IPage<Book> page); }
-
编写映射器,例如:
<?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="com.sp.mapper.BookMapper"> <select id="findByPage" resultType="book"> select * from tb_book </select> </mapper>
-
编写测试,例如:
@Test public void test07(){ Page<Book> page = new Page<>(1,3); IPage<Book> bookPage = bookMapper.findByPage(page); List<Book> books = bookPage.getRecords(); }
pageHelper分页
-
添加jar包
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency>
-
添加以下内容,例如:
@Configuration public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor().setCountSqlParser(new JsqlParserCountOptimize(true)); } @Bean public PageInterceptor pageInterceptor(){ return new PageInterceptor(); } }
-
编写映射接口,同上
-
测试,例如:
@Test public void test08(){ PageHelper.startPage(2,3); List<Book> b1 = bookMapper.selectList(null); PageInfo<Book> pageInfo = new PageInfo<>(b1); List<Book> books = pageInfo.getList(); System.out.println("每⻚显示条数:"+pageInfo.getPageSize()); System.out.println("当前⻚的条数:"+pageInfo.getSize()); System.out.println("总条数:"+pageInfo.getTotal()); System.out.println("总⻚数:"+pageInfo.getPages()); System.out.println("上⼀⻚:"+pageInfo.getPrePage()); System.out.println("下⼀⻚:"+pageInfo.getNextPage()); System.out.println("当前⻚:"+pageInfo.getPageNum()); }