Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
spring boot来简化spring应用开发,约定大于配置,去繁从简,just run就能创建一个独立的,产品级别的应用。
Spring Boot 优点非常多,如:
**spring: **
一个IOC和AOP框架,项目中对象的管理权交给了容器。有七大模块。
springmvc:
是spring中的一个web模块。采用的mvc模式,通过DispatcherServer前端控制器、ModelAndView 模型和视图、ViewResolver视图解析器实现了web开发。
springboot:
Spring 和 SpringMVC 的问题在于需要配置大量的参数。Spring Boot 通过一个自动配置和启动的项来目解决这个问题。为了更快的构建产品就绪应用程序,Spring Boot 提供了一些非功能性特征。
springboot不建议使用jsp作为开发模板,默认使用thymeleaf模板引擎作为动态网页技术。
工程目录:
resources目录:
static: 存放静态内容
templates:模板引擎的动态网页内容
application.properties: 全局配置文件
springboot中页面的加载顺序:
首页加载顺序:static > public > templates
错误页面加载:在static或 public或 templates中创建error目录,定义4xx.html、5xx.html即可
springboot中的启动器:
https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/using-spring-boot.html#using-boot
Name | Description |
---|---|
spring-boot-starter |
Core starter, including auto-configuration support, logging and YAML 核心启动器,包括自动配置支持、日志记录和YAML |
spring-boot-starter-activemq |
Starter for JMS messaging using Apache ActiveMQ |
spring-boot-starter-amqp |
Starter for using Spring AMQP and Rabbit MQ |
spring-boot-starter-aop |
Starter for aspect-oriented programming with Spring AOP and AspectJ |
spring-boot-starter-artemis |
Starter for JMS messaging using Apache Artemis |
spring-boot-starter-batch |
Starter for using Spring Batch |
spring-boot-starter-cache |
Starter for using Spring Framework’s caching support |
spring-boot-starter-data-cassandra |
Starter for using Cassandra distributed database and Spring Data Cassandra |
spring-boot-starter-data-cassandra-reactive |
Starter for using Cassandra distributed database and Spring Data Cassandra Reactive |
spring-boot-starter-data-couchbase |
Starter for using Couchbase document-oriented database and Spring Data Couchbase |
spring-boot-starter-data-couchbase-reactive |
Starter for using Couchbase document-oriented database and Spring Data Couchbase Reactive |
spring-boot-starter-data-elasticsearch |
Starter for using Elasticsearch search and analytics engine and Spring Data Elasticsearch |
spring-boot-starter-data-jdbc |
Starter for using Spring Data JDBC |
spring-boot-starter-data-jpa |
Starter for using Spring Data JPA with Hibernate |
spring-boot-starter-data-ldap |
Starter for using Spring Data LDAP |
spring-boot-starter-data-mongodb |
Starter for using MongoDB document-oriented database and Spring Data MongoDB |
spring-boot-starter-data-mongodb-reactive |
Starter for using MongoDB document-oriented database and Spring Data MongoDB Reactive |
spring-boot-starter-data-neo4j |
Starter for using Neo4j graph database and Spring Data Neo4j |
spring-boot-starter-data-r2dbc |
Starter for using Spring Data R2DBC |
spring-boot-starter-data-redis |
Starter for using Redis key-value data store with Spring Data Redis and the Lettuce client |
spring-boot-starter-data-redis-reactive |
Starter for using Redis key-value data store with Spring Data Redis reactive and the Lettuce client |
spring-boot-starter-data-rest |
Starter for exposing Spring Data repositories over REST using Spring Data REST |
spring-boot-starter-data-solr |
Starter for using the Apache Solr search platform with Spring Data Solr |
spring-boot-starter-freemarker |
Starter for building MVC web applications using FreeMarker views |
spring-boot-starter-groovy-templates |
Starter for building MVC web applications using Groovy Templates views |
spring-boot-starter-hateoas |
Starter for building hypermedia-based RESTful web application with Spring MVC and Spring HATEOAS |
spring-boot-starter-integration |
Starter for using Spring Integration |
spring-boot-starter-jdbc |
Starter for using JDBC with the HikariCP connection pool |
spring-boot-starter-jersey |
Starter for building RESTful web applications using JAX-RS and Jersey. An alternative to spring-boot-starter-web |
spring-boot-starter-jooq |
Starter for using jOOQ to access SQL databases. An alternative to spring-boot-starter-data-jpa or spring-boot-starter-jdbc |
spring-boot-starter-json |
Starter for reading and writing json |
spring-boot-starter-jta-atomikos |
Starter for JTA transactions using Atomikos |
spring-boot-starter-jta-bitronix |
Starter for JTA transactions using Bitronix. Deprecated since 2.3.0 |
spring-boot-starter-mail |
Starter for using Java Mail and Spring Framework’s email sending support |
spring-boot-starter-mustache |
Starter for building web applications using Mustache views |
spring-boot-starter-oauth2-client |
Starter for using Spring Security’s OAuth2/OpenID Connect client features |
spring-boot-starter-oauth2-resource-server |
Starter for using Spring Security’s OAuth2 resource server features |
spring-boot-starter-quartz |
Starter for using the Quartz scheduler |
spring-boot-starter-rsocket |
Starter for building RSocket clients and servers |
spring-boot-starter-security |
Starter for using Spring Security |
spring-boot-starter-test |
Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito |
spring-boot-starter-thymeleaf |
Starter for building MVC web applications using Thymeleaf views |
spring-boot-starter-validation |
Starter for using Java Bean Validation with Hibernate Validator |
spring-boot-starter-web |
Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container |
spring-boot-starter-web-services |
Starter for using Spring Web Services |
spring-boot-starter-webflux |
Starter for building WebFlux applications using Spring Framework’s Reactive Web support |
spring-boot-starter-websocket |
Starter for building WebSocket applications using Spring Framework’s WebSocket support |
spring-boot-starter-actuator | Starter for using Spring Boot’s Actuator which provides production ready features to help you monitor and manage your application |
spring-boot-starter-tomcat | Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web |
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
第三方依赖添加到springboot中 :
https://mvnrepository.com/
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.2version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.22version>
dependency>
# 工程目录
springboot-03
|--src
|--main
|--java
|--com.newer.springboot
|--config
|--controller
|--mapper
|--model
|--service
|--Springboot03Application
|--resources
|--static
|--templates
|--application.properties
|--webapp
|--WEB-INF
|--views
|--index.jsp
|--test
|--target
|--pom.xml
改pom.xml
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
dependency>
<dependency>
<groupId>org.apache.tomcat.embedgroupId>
<artifactId>tomcat-embed-jasperartifactId>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-tomcatartifactId>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
修改全局配置application.proteties
# 设置端口号
server.port=80
# 设置工程路径 http://localhost:8088/springboot
# server.servlet.context-path=/springboot
# 设置spring mvc
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
编写Controller层:
@Controller
public class UserController {
@RequestMapping({"/index","/"})
public String index(){
return "index";
}
}
使用idea中的maven插件启动项目
命令:mvn spring-boot:run
需要了解
常见问题:
打不到jsp页面?
IDEA2018.3配置的maven版本3.3+以上,3.6.0以下
网络问题无法加载依赖
启动jsp工程:mvn spring-boot:run
返回的是页面的名称,不是真实的页面内容?
只能使用@Controller注解,不要使用@RestController或@ResponseBody
@Controller
public class UserController {
//设置欢迎页 http://localhost/springboot/index.jsp
@RequestMapping({"/index","/"})
public String index(){
return "index";
}
}
1) 直接运行main方法
2) 使用mvn插件或命令:mvn spring-boot:run
3) 打包后运行: java -jar 方式
打包命令:mvn package
运行命令:java -jar springboot-01-0.0.1-SNAPSHOT.jar
使用mvn插件(使用的是内置tomcat): mvn spring-boot:run
配置外置的tomcat启动(了解)
a. 修改主启动类
@SpringBootApplication
public class Springboot04Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Springboot04Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Springboot04Application.class, args);
}
}
b. 配置外部tomcat运行war包:
解决tomcat控制台乱码问题:
在tomcat服务中修改vm options: -Dfile.encoding=UTF-8
创建数据表
create table t_user
(
id int(10) auto_increment comment '编号'
primary key,
username varchar(50) default '' not null comment '用户名',
password varchar(50) default '' not null comment '密码',
createTime datetime not null on update CURRENT_TIMESTAMP comment '创建时间'
)
comment 't_user' charset = utf8mb4;
改pom.xml
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.0.1version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.22version>
dependency>
改配置文件application.properties
# 设置数据库
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
# 设置mybatis(用于xml编码时)
mybatis.type-aliases-package=com.newer.springboot.model
mybatis.mapper-locations=classpath:/mapper/*.xml
写实体类
@Data
public class User {
private Integer id;
private String username;
private String password;
private Date createTime;
}
写mapper接口
@Mapper
public interface UserMapper {
@Select("select * from t_user where id = #{id}")
User findById(@Param("id") Integer id);
}
写service接口
public interface UserService {
User findById(Integer id);
}
写servicer接口的实现类
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public User findById(Integer id) {
return userMapper.findById(id);
}
}
写controller层
@Controller
public class UserController {
@Autowired
UserService userService;
//设置欢迎页 http://localhost/springboot/index.jsp
@RequestMapping({"/index","/"})
public String index(){
return "index";
}
@RequestMapping("/getUser")
@ResponseBody
public User getUserById(){
User user = userService.findById(1);
return user;
}
}
测试
官网: https://mp.baomidou.com/
mybtais-plus 为简化开发而生,只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
创建数据表
改pom
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.2version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.3.0version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.22version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
改全局配置文件application.properties
# 设置端口号
server.port=80
# 设置数据库
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
# 设置mybatis
mybatis.type-aliases-package=com.newer.springboot.model
mybatis.mapper-locations=classpath:/mapper/*.xml
写实体类
@Data
@TableName("t_user")
public class User {
@TableId
private Integer id;
private String username;
private String password;
@TableField("createTime")
private Date createTime;
}
mapper接口
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
写servicer接
public interface UserService extends IService<User> {
}
写servicer接口实现类
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}
写controller层
@RestController
public class UserController {
@Autowired
UserService userService;
@RequestMapping("/getUser")
public User getUserById(){
User user = userService.getById(1);
return user;
}
@RequestMapping("/getUserList")
public List<User> getUsers(){
List<User> users = userService.list();
return users;
}
}
测试
官网: https://www.webjars.org/
方式一:常规方式
方式二:webjars方式
修改pom.xml
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>webjars-locator-coreartifactId>
dependency>
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>jqueryartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>bootstrapartifactId>
<version>3.4.1version>
dependency>
引用webjars资源
<script src="webjars/jquery/jquery.js">script>
<link rel="stylesheet" href="webjars/bootstrap/css/bootstrap.css"/>
测试
需要了解:
springboot中的注解
springboot环境切换
分页
常见问题:
session: 会话对象。唯一的id
appche shiro: java权限框架
spring-security: 以spring为基础
高并发解决订单编号的几种方式
标识列,主键,自动增长
随机数类
rownum、序列sequenct。
reids缓存 单线程,运行在内存中的nosql数据库
使用各大厂商的方案:雪花算法
YAML是JSON的超集,springboot默认使用YAML文件作为应用程序的配置文件,配置文件名:application.yml
开发的项目存在多个环境,比如开发环境(dev)、生产环境(prod)、测试环境(test)。
创建三个yml文件
application.yml – 主环境文件(相当于application-default.yml)
# 主环境切换
spring:
profiles:
active: dev
application-dev.yml – 开发环境文件
# 设置端口(注意在属性值之间加空格)
server:
port: 80
# 工程名称
spring:
application:
name: springboot
application-prod.yml – 生产环境文件
# 设置端口(注意在属性值之间加空格)
server:
port: 8088
# 工程名称
spring:
application:
name: springboot
1. @SpringBootApplication: 运行项目
@SpringBootConfiguration -- 读取springboot中的配置文件
@EnableAutoConfiguration -- 读取自动配置中的配置文件
@ComponentScan -- 包扫描(默认把主包下的文件扫描进行)
@ControllerAdvice
@CookieValue
@CrossOrigin
@DeleteMapping
@ExceptionHandler
@GetMapping
@InitBinder
@Mapping
@MatrixVariable
@ModelAttribute
@package-info
@PatchMapping
@PathVariable
@PostMapping
@PutMapping
@RequestAttribute
@RequestBody
@RequestHeader
@RequestMapping
@RequestParam
@RequestPart
@ResponseBody
@ResponseStatus
@RestController
@RestControllerAdvice
@SessionAttribute
@SessionAttributes
@Delete
@Insert
@Many
@Mapper
@One
@Param
@Result
@ResultMap
@Results
@ResultType
@Select
@Update
自己写分页工具类: PagerUitl.java
使用分页插件: PageHelper
官网:https://github.com/pagehelper/pagehelper-spring-boot
全局异常处理
数据统一封装
swagger2接口文档
测试工具postman使用
为什么要封装数据
为了提高开发组的效率,统一为APP端、Web端、Java端制定开发规范。
{
"code": "返回的状态码",
"iserror":"是否有错误",
"msg": "返回的信息描述",
"data": "返回的数据"
}
怎么封装
区间 | 表示的错误 |
---|---|
0000 | 表示响应成功 |
1000 ~ 1999 | 表示参数错误 |
2000 ~ 2999 | 表示用户错误 |
3000 ~ 3999 | 表示接口异常 |
4000 | 表示服务端错误 |
/**
* @desc: 状态码
*
*/
public enum EnumCode {
/**
* 200请求成功
*/
OK(200, "请求成功"),
/**
* 303登录失败
*/
LOGIN_FAIL(303, "登录失败"),
/**
* 400请求参数出错
*/
BAD_REQUEST(400, "请求参数出错"),
/**
* 401没有登录
*/
UNAUTHORIZED(401, "没有登录"),
/**
* 403没有权限
*/
FORBIDDEN(403, "没有权限"),
/**
* 410已被删除
*/
GONE(410, "已被删除"),
/**
* 423已被锁定
*/
LOCKED(423, "已被锁定"),
/**
* 500服务器出错
*/
INTERNAL_SERVER_ERROR(500, "服务器出错"),
/**
* 异常
*/
EXCPTION_ERROR(4001, "异常");
private final Integer value;
private final String text;
private EnumCode(Integer value, String text) {
this.value = value;
this.text = text;
}
/**
* 获取value
*/
public Integer getValue() {
return this.value;
}
/**
* 获取Text
*/
public String getText() {
return this.text;
}
}
创建一个结果集返回类
/**
* 统一响应的数据返回类
*/
public class ResponseResult implements Serializable {
private Integer code;
private Boolean hasError;
private String message;
private Object data;
controller层
@RestController
public class UserController {
/**
* restful 风格(不能使用动名,只能是名词)
* 对于实体对象,通过url就能返应状态
* 请求方式+实体名
*
* getMapping: 获取数据 /users /user/1
* postMapping: 添加数据 /user
* putMapping: 修改数据 /user/1
* deleteMapping: 删除数据 /user/1
*
* @return
*/
@GetMapping("/users")
public ResponseResult getUsers() {
List<User> userList = new ArrayList<>();
userList.add(new User(1, "a", "123"));
userList.add(new User(2, "b", "123"));
userList.add(new User(3, "c", "123"));
userList.add(new User(4, "d", "123"));
userList.add(new User(5, "e", "123"));
return new ResponseResult().setCode(200)
.setHasError(false)
.setMessage(null)
.setData(userList);
}
// 演示错误返回结果
@GetMapping("/user/{id}")
public ResponseResult getUserById(@PathVariable("id") int id) {
return new ResponseResult()
.setCode(2001)
.setHasError(true)
.setMessage("用户密码错误")
.setData(null);
}
}
什么是异常
程序中出现的错误,称为异常
分类:Error(硬件)和Exception(运行时异常)
全局异常类:BasicErrorController
SpringBoot内置了一个BasicErrorController对异常进行统一的处理,当在页面发生异常的时候会自动把请求转到/error。
也可以自定义页面内容,只需在classpath路径下新建error页面即可。
全局异常解析器:HandlerExceptionResolver
自定义异常
创建一个MyException类,继承Exception类
重写构造方法
统一异常处理器(GlobalErrorHandler)
@ControllerAdvice 限定范围 例如扫描某个控制层的包
@RestControllerAdvice 全部异常处理返回json
@ExceptionHandler 指定异常 例如指定处理运行异常,用于方法上。
全局异常的开发步骤
自定义异常解析器继承HandlerExceptionResolver
/**
* 自定义一个异常解析器
* 作用:统一处理框架中的异常信息
*/
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {
ModelAndView mv = new ModelAndView();
mv.setViewName("error");
if(e instanceof MyException){
mv.addObject("ex",e.getMessage());
}else if(e instanceof IOException){
mv.addObject("ex","IO流异常");
}else{
mv.addObject("ex", "未知异常");
}
return mv;
}
}
创建统一的异常处理类(把controlelr中的一个异常处理方法提升到全局方法)
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler
public String handlerException(Exception e, Model model){
if(e instanceof MyException){
model.addAttribute("ex", e.getMessage());
}else if(e instanceof Exception){
model.addAttribute("ex", "哈哈哈,我就是黑客!");
}
return "/error/error";
}
}
在controller层抛出异常
@RequestMapping("/hello")
public String hello() throws Exception {
throw new MyException("你的网站错误!");
// return "Hello World!";
}
总结:开发时只需要在mappr层、server层、controller层中抛出异常,不需要处理。
改pom.xml
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.6.0version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.6.0version>
dependency>
改应用程全局配置application.propertis
# swagger配置
swagger.enable = true
swagger全局配置
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Value("${swagger.enabled}")
private boolean enableSwagger;
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//是否开启
.enable(enableSwagger)
.select()
//扫描的路径包,设置basePackage会将包下的所有被@Api标记类的所有方法作为api
.apis(RequestHandlerSelectors.basePackage("com.newer.springboot.controller"))
//指定路径处理PathSelectors.any()代表所有的路径
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
//设置文档标题
.title("Spring-boot项目")
//文档描述
.description("V1.0接口规范")
//服务条款URL
.termsOfServiceUrl("http://127.0.0.1:80/")
//版本号
.version("1.0.0")
.build();
}
}
controller层使用
@RestController
@Api(value="用户接口",description="用户接口测试")
public class UserController {
@RequestMapping("/hello")
@ApiOperation(value="测试",httpMethod="GET",notes="测试")
public String hello() throws Exception {
throw new MyException("你的网站错误!");
// return "Hello World!";
}
/**
* restful 风格(不能使用动名,只能是名词)
* 对于实体对象,通过url就能返应状态
* 请求方式+实体名
*
* getMapping: 获取数据 /users /user/1
* postMapping: 添加数据 /user
* putMapping: 修改数据 /user/1
* deleteMapping: 删除数据 /user/1
*
* @return
*/
@GetMapping("/users")
@ApiOperation(value="查询所有用户",httpMethod="GET",notes="查看所有用户详情")
public ResponseResult getUsers() {
List<User> userList = new ArrayList<>();
userList.add(new User(1, "a", "123"));
userList.add(new User(2, "b", "123"));
userList.add(new User(3, "c", "123"));
userList.add(new User(4, "d", "123"));
userList.add(new User(5, "e", "123"));
return new ResponseResult().setCode(200).setHasError(false).setMessage(null).setData(userList);
}
// 演示错误返回结果
@GetMapping("/user/{id}")
@ApiOperation(value="根据id获取用户",httpMethod="GET",notes="查看用户错误演示")
public ResponseResult getUserById(@PathVariable("id") int id) {
return new ResponseResult()
.setCode(2001)
.setHasError(true)
.setMessage("用户密码错误")
.setData(null);
}
}
测试
http://localhost/swagger-ui.html
Aop日志
快速实现事务
拦截器Intercepote
数据校验
了解部分:
定时任务
发送email
解决前后端分离项目的后台跨域问题
了解RestTemplate进行服务调用
什么是事务?
把多条sql语句当作一个逻辑执行单元,要么同时成功,要么同时失败!
事务四个特性
原子性(atomic):要么都成功,要么都失败
一致性(consistent):事务提交前后数据保持一致
隔离性(isolate):事务互相不影响
持久性(durable):一旦提交,永久保存,不能回滚
事务并发产生的问题:
脏读:一个事务读取另一个事务未提交的一条数据
幻读:一个事务读取另一个事务添加的多条数据
不可重复读:一个事务读取另一个事务修改的一条数据
事务4种隔离性(级别越低数字越小):
事务7种传播机制
传播行为 | 意义 |
---|---|
REQUIRED | 如果当前有事务则加入事务,如果没有事务,则创建一个新的(默认值) |
NOT_SUPPORTED | 支持当前事务,如果没有当前事务,就以非事务方法执行,相当于没有事务 |
REQUIRES_NEW | 不管是否存在事务,都创建一个新的事务,原来的方法挂起,新的方法执行完毕后,继续执行老的事务 |
MANDATORY | 必须在一个已有的事务中执行,否则报错 |
NEVER | 必须在一个没有的事务中执行,否则报错 |
SUPPORTS | 其他bean调用这个方法时,如果声明了事务,则就用这个事务,如果没有声明事务,那就不用事务 |
NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作 |
在springboot开发时一般使用数据库的默认隔离级别和默认传播行为,源码如下:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
// 默认传播行为
Propagation propagation() default Propagation.REQUIRED;
// 默认隔离级别
Isolation isolation() default Isolation.DEFAULT;
int timeout() default -1;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
事务的注解
@Transactional : 一般用于service业务层
@Service("userService")
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,readOnly = false )
public class UserServiceImpl implements UserService {
@Resource
UserMapper userMapper;
@Override
public User findById(int id) {
User user = userMapper.selectById(id);
return user;
}
@Override
public List<User> findAll() {
return userMapper.selectAll();
}
@Override
public Boolean updateById(String username, int id) throws SQLException {
Boolean flag = userMapper.updateById(username, id);
// 事务默认只对运行时的异常有效
// SQLSQLException不是runtimeException的子类
throw new SQLException("修改失败");
// throw new RuntimeException("修改失败");
}
}
springboot中的事务坑
默认只对运行时异常有效。对sqlException无效。
@Transactional(rollbackFor = Exception.class)
为什么前后台都要进行数据校验?
前台校验可以解决用户输入问题,后台校验正确性和准确性,一般可以跳过前台的验证机制。为了避免网站受到攻击。
springboot中校验数据开发步骤
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-validationartifactId>
dependency>
数据校验注解
@AssertFalse
@AssertTrue
@DecimalMax
@DecimalMin
@Digits
@Email
@Future
@FutureOrPresent
@Max
@Min
@Negative
@NegativeOrZero
@NotBlank
@NotEmpty
@NotNull
@Null
@Past
@PastOrPresent
@Pattern
@Positive
@PositiveOrZero
@Size
日期格式化注解
@JsonFormat:后台传到前台的json格式的日期
@DateTimeFormat:前台传到后台的日期格式
注解:@Validated
@PostMapping("/user")
@ApiOperation(value = "添加用户", httpMethod = "POST", notes = "添加用户详情")
public ResponseResult addUser(@Validated User user) {
log.info("user===>"+user);
return new ResponseResult().setCode(200).setHasError(false).setMessage(null).setData(null);
}
Spring Boot默认使用slf4j日志门面+LogBack日志实现,也可以切换为其它日志框架。
常见的日志框架有:JUL , JCL , Jboss-logging , logback , log4j , log4j2 , slf4j等等,他们的分类如下:
日志门面(日志的抽象层) | 日志实现 |
---|---|
JCL,SLF4J,Jboss-logging | Log4j , JUL(java.util.logging ) , Log4j2, Logback |
JCL是Apache公司开发的一个框架,Jakarta小组开发的,Spring Framework在使用,但是2014年已经停止更新了。SLF4J , Log4j , Logback是同一个人写的,这个人想优化Log4j,但是认为重新写比较麻烦,于是写了SLF4J这个抽象层日志框架,又写了Logback这个实现类。Log4j2也是Apache公司的,好多框架都没适配。Hibernate底层使用Jboss-logging实现。
在控制台打印日志
方式一:使用lombak日志注解
@Slf4j // 统一日志注解
方式二:
private static final Logger log = LoggerFactory.getLogger(UserController.class);
如何将日志信息存储到文件
# 日志文件路径
# logging.path=d:/workspace/springboot/mylog
# 日志文件名(默认名springboot.log)
# logging.file=mylog.log
如果两者都配置了:logging.file=mylog.log、logging.path=D:/data/mylog,此时并不会在d盘下生成日志文件,只会在项目的根目录下创建一个mylog.log的文件。
其原因是,没有logback-spring.xml配置文件,系统只认识logging.file,不认识logging.path。
logback-spring.xml
<configuration>
<springProfile name="dev">
<property name="LOG_HOME" value="d:/logs/dev/" />
springProfile>
<springProfile name="prd">
<property name="LOG_HOME" value="d:/logs/prd/" />
springProfile>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{30} - %msg%npattern>
<charset>UTF-8charset>
encoder>
appender>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{30} - %msg%npattern>
<charset>UTF-8charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/mysprintboot_%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>90maxHistory>
rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFOlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="file" />
root>
configuration>
如何设置日志级别
日志级别总共有TRACE < DEBUG < INFO < WARN < ERROR < FATAL ,且级别是逐渐提供,如果日志级别设置为INFO,则意味TRACE和DEBUG级别的日志都看不到。Spring Boot默认级别就是INFO。
logging.level.root=warn
如何设置日志格式
logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n
logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n
日志格式如下:
占位符 | 描述 |
---|---|
%d{yyyy-MM-dd HH:mm:ss.SSS} | 日期 |
%5p | 日志级别,5位字符长度显示,如果内容占不满5位则内容右对齐并在左侧补空格 |
%-5p | 5位字符长度显示日志级别,如果内容占不满5位则内容左对齐并在右侧补空格 -代表左对齐 |
%logger | 日志所在包和类 |
%M | 日志所在方法名 |
%L | 日志所在代码行 |
%m | 日志正文 |
%n | 换行 |
项目中为什么要使用日志功能。
记录用户的一系列操作,存储到数据库中。
日志功能的实现方式
aop方式实现
拦截器实现
过滤器实现
AOP日志:
改pom.xml
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
创建一个Aspect通知类
写一个日志注解(非必需)
@Target({TYPE, METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LoginLog {
String value();
}
Aspect通知类
@Aspect // 切面 通知+切入点
@Component
@Slf4j
public class LoginAspect {
// 指定切入点
@Pointcut("@annotation(com.newer.springboot.aop.LoginLog)")
public void loginPointCat() {
}
// 保存登录之后的用户信息
// 后置通知
@AfterReturning("loginPointCat()")
public void saveUserLog(JoinPoint joinPoint) {
// 获得request对象
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpSession session = request.getSession();
// 获取用户
// User user = (User) session.getAttribute("user");
// 获取参数
Object[] args = joinPoint.getArgs();
log.info("params:"+ Arrays.toString(args));
// 操作的方法:
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
String value = method.getAnnotation(LoginLog.class).value();
log.info("method:"+value);
// 操作用户的IP
String remoteAddr = request.getRemoteAddr();
log.info("ipAddress:"+remoteAddr);
// 操作时间
// 存数据库
}
}
在目标方法中使用
@RequestMapping("/login")
@LoginLog("login") // 使用日志注解
public String login(Model model) {
model.addAttribute("username", "admin");
model.addAttribute("password", "123456");
return "index";
}
aop方式可以在任意类上实现日志业务的打印或存储,如果我们只需要controller层对日志处理,可以使用拦截器。步骤如下:
改pom.xml
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.60version>
dependency>
创建类实现HanlerInterceptor接口
/**
* 登录日志拦截器
*/
@Slf4j
public class WebInterceptor implements HandlerInterceptor {
// 方法执行前拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 请求路径
String url = request.getRequestURI();
// 获取请求参数
String paramData = JSON.toJSONString(request.getParameterMap(),SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
// 请求客户ip
String clientIp = request.getRemoteAddr();
// 请求方式:get/post/put/delete
String methodName = request.getMethod();
// 设置请求的开始时间
request.setAttribute("STARTTIME", System.currentTimeMillis());
StringBuffer content = new StringBuffer();
content.append("url="+url);
content.append(" ,paramData=").append(paramData);
content.append( ", clientIp=").append(clientIp);
content.append(" ,HTTP_METHOD=").append(methodName);
log.info("content:"+content);
return true; // 拦截开关
}
// 视图渲染前拦截
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
// 方法执行后拦截
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 响应状态
int status = response.getStatus();
//当前时间
long currentTime = System.currentTimeMillis();
long startTime = Long.valueOf(request.getAttribute("STARTTIME").toString());
System.out.println("time2:"+(currentTime - startTime)+"ms");
}
}
配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public HandlerInterceptor handlerInterceptor() {
return new WebInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(handlerInterceptor())
// 拦截所有方法
.addPathPatterns("/**")
// 以下url不拦截
.excludePathPatterns("/", "/login", "/error", "/logout", "/static/**", "/error/**");
}
}
官网:https://www.hutool.cn/
Hutool是一个Java工具包类库,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类。
包含组件
模块 | 介绍 |
---|---|
hutool-aop | JDK动态代理封装,提供非IOC下的切面支持 |
hutool-bloomFilter | 布隆过滤,提供一些Hash算法的布隆过滤 |
hutool-cache | 简单缓存实现 |
hutool-core | 核心,包括Bean操作、日期、各种Util等 |
hutool-cron | 定时任务模块,提供类Crontab表达式的定时任务 |
hutool-crypto | 加密解密模块,提供对称、非对称和摘要算法封装 |
hutool-db | JDBC封装后的数据操作,基于ActiveRecord思想 |
hutool-dfa | 基于DFA模型的多关键字查找 |
hutool-extra | 扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等) |
hutool-http | 基于HttpUrlConnection的Http客户端封装 |
hutool-log | 自动识别日志实现的日志门面 |
hutool-script | 脚本执行封装,例如Javascript |
hutool-setting | 功能更强大的Setting配置文件和Properties封装 |
hutool-system | 系统参数调用封装(JVM信息等) |
hutool-json | JSON实现 |
hutool-captcha | 图片验证码实现 |
hutool-poi | 针对POI中Excel和Word的封装 |
hutool-socket | 基于Java的NIO和AIO的Socket封装 |
可以根据需求对每个模块单独引入,也可以通过引入hutool-all
方式引入所有模块。
Maven安装
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.3.9version>
dependency>