<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
package com.qf.HomeWork.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 该切面用于统计方法执行的时长
*/
@Aspect
@Component
@Slf4j
public class TimeAspect {
//1.定义切点
@Pointcut("execution(* com.qf.HomeWork.controller.UserController.*(..))")
public void timepointcut(){};
//2.定义通知
@Around("timepointcut()")
public Object calculateTime(ProceedingJoinPoint pjp) throws Throwable {
long start =System.currentTimeMillis();
Object proceed = pjp.proceed();
//获取当前调用的目标方法
Signature signature = pjp.getSignature();
long end =System.currentTimeMillis();
log.info("{}请求消耗的时长为:{}ms",signature,(end-start));
return proceed;
}
}
先写一个过滤器的类 若用原生态Filter或者servlet 必须在 主启动类上面加@ServletComponentScan注解
package com.qf.HomeWork.filter;
import com.qf.HomeWork.entity.Info;
import com.qf.HomeWork.mapper.InfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Slf4j
@Component
public class InfoFilter implements Filter {
@Autowired
private InfoMapper infoMapper;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("============经过了InfoFilter过滤器================");
HttpServletRequest req= (HttpServletRequest) request;
long start = System.currentTimeMillis();
log.info("起始时间戳:{}",start);
String url = req.getRequestURI().toString();
log.info("请求的url={}",url);
String ip = req.getRemoteAddr();
log.info("请求的ip={}",ip);
String method = req.getMethod();
log.info("请求的方式={}",method);
chain.doFilter(request,response);
long end = System.currentTimeMillis();
Long time = end - start;
log.info("请求所用时间为{}ms",time);
infoMapper.add(new Info(null,url,ip,method,time.toString()));
log.info("============离开了InfoFilter过滤器================");
}
}
然后在配置类里,注册此过滤器,然后就能在 请求的时候经过过滤器
package com.qf.HomeWork.config;
import com.qf.HomeWork.filter.CheckPasswordFilter;
import com.qf.HomeWork.filter.CheckUserNameFilter;
import com.qf.HomeWork.filter.InfoFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Autowired
private InfoFilter infoFilter;
//将InfoFilter对象放入注册器中,将注册器放入IOC容器中,让springboot拿到,然后调用选取有效的过滤器的执行链,遍历执行其方法。
@Bean
public FilterRegistrationBean<InfoFilter> infoFilterFilterRegistrationBean(){
FilterRegistrationBean<InfoFilter> registrationBean = new FilterRegistrationBean<>();
//要注册的filter的对象
registrationBean.setFilter(infoFilter);
//处理filter的url路径
registrationBean.addUrlPatterns("/*");
//设置优先级 越小优先级越高
registrationBean.setOrder(Integer.MIN_VALUE);
// 把注册器这个类的对象注入IOC容器里供Spring自行调用
return registrationBean;
}
@Bean
public FilterRegistrationBean<CheckUserNameFilter> checkUsernameFilterFilterRegistrationBean(){
FilterRegistrationBean<CheckUserNameFilter> registrationBean = new FilterRegistrationBean<>();
//要注册的filter的对象
registrationBean.setFilter(new CheckUserNameFilter());
//处理filter的url路径
registrationBean.addUrlPatterns("/h1","/login/dologin");
registrationBean.setOrder(2);
return registrationBean;
}
@Bean
public FilterRegistrationBean<CheckPasswordFilter> checkPasswordFilterFilterRegistrationBean(){
FilterRegistrationBean<CheckPasswordFilter> registrationBean = new FilterRegistrationBean<>();
//要注册的filter的对象
registrationBean.setFilter(new CheckPasswordFilter());
//处理filter的url路径
registrationBean.addUrlPatterns("/h1","/login/dologin");
registrationBean.setOrder(3);
return registrationBean;
}
}
写一个拦截器的类
package com.qf.HomeWork.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("==========MyInterceptor preHandle==============");
//放行该请求
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("==========MyInterceptor postHandle==============");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("==========MyInterceptor afterCompletion==============");
}
}
注册拦截器
package com.qf.HomeWork.config;
import com.qf.HomeWork.interceptor.MyInterceptor;
import com.qf.HomeWork.interceptor.MyInterceptor2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
MyInterceptor myInterceptor;
@Autowired
MyInterceptor2 myInterceptor2;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加拦截器
registry.addInterceptor(myInterceptor)
//拦截路径
.addPathPatterns("/login/dologin")
//优先级
.order(10);
registry.addInterceptor(myInterceptor2)
.addPathPatterns("/login/dologin")
.order(1);
}
}
spring:
#图片上传大小 肯定存在 MultipartProperties这个类
servlet:
multipart:
#单个文件最大大小
max-file-size: 10MB
#全部文件总大小
max-request-size: 50MB
qf:
fileupload:
path: F:\pathpng\
package com.qf.HomeWork.controller;
import com.qf.HomeWork.util.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@RestController
@RequestMapping("/up")
@Slf4j
public class UploadController {
@Value("${qf.fileupload.path}")
private String picdir;
@RequestMapping("/pic")
public ResultVo upload(MultipartFile photo) throws IOException {
log.info("接收到文件为:{}",photo.getOriginalFilename());
String extName = photo.getOriginalFilename().substring(photo.getOriginalFilename().lastIndexOf("."));
String picPath=picdir;
String filepath=picPath+ UUID.randomUUID().toString().replace("-","")+extName;
log.info("上传路径为:{}",filepath);
//存放文件
photo.transferTo(new File(filepath));
return ResultVo.ok(1,photo.getName());
}
}
package com.qf.HomeWork.controller;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@RestController
@RequestMapping("/down")
@Slf4j
public class DownLoadController {
@Value("${qf.fileupload.path}")
private String filedir;
@RequestMapping("/pic")
public void download(String picname, HttpServletResponse resp) throws IOException {
//1.获取文件名对应文件的路径
String filepath=filedir+picname;
resp.addHeader("Content-Disposition","attachment;filename="+picname);
log.info("文件路径:{}",filepath);
//2. 将要下载的文件的字节数据拷贝到response对象的输出流中即可,不写响应头就和验证码响应浏览器原理相同
IOUtils.copy(new FileInputStream(filepath), resp.getOutputStream());
}
}
先导依赖
<dependency>
<groupId>com.baomidougroupId>
<artifactId>kaptcha-spring-boot-starterartifactId>
<version>1.1.0version>
dependency>
yml
#验证码的配置
kaptcha:
height: 50
width: 200
content:
length: 2
source: abcdefghjklmnopqrstuvwxyz23456789
space: 2
font:
color: black
name: Arial
size: 40
background-color:
from: lightGray
to: white
border:
enabled: true
color: black
thickness: 1
#自定义验证码超时时间
qf:
kapchar:
timeout: 60
测试
package com.qf.HomeWork.controller;
import com.baomidou.kaptcha.Kaptcha;
import com.baomidou.kaptcha.exception.KaptchaTimeoutException;
import com.qf.HomeWork.util.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/login")
@Slf4j
public class KapcherController {
@Autowired
private Kaptcha kaptcha;
@Value("${qf.kapchar.timeout}")
private Integer timeout;
@GetMapping("/kapchar")
public void kapchar(){
kaptcha.render();
}
@GetMapping("/validate")
public ResultVo validate(@RequestParam("code") String code){
log.info("入参为:code={}",code);
try {
boolean flag = kaptcha.validate(code,10);
log.info("验证码校验结果,flag={}",flag);
return ResultVo.ok(1,flag);
}catch (Exception e){
e.printStackTrace();
return ResultVo.error(-1,false);
}
}
@PostMapping("/dologin")
public ResultVo dologin(@RequestParam("username") String username,@RequestParam("password")String password,@RequestParam("captcha")String captcha) {
log.info("入参为:username={},password={},captcha={}", username, password, captcha);
//校验验证码
try {
log.info("验证码有效时间为:timeout={}",timeout);
boolean flag = kaptcha.validate(captcha,timeout);
log.info("验证码校验结果,flag={}", flag);
}catch (KaptchaTimeoutException e) {
e.printStackTrace();
return ResultVo.error(-1, "验证码超时");
}
catch (Exception e) {
e.printStackTrace();
return ResultVo.error(-1, "验证码错误");
}
//判断用户名密码是否正确
if (username.equals("luffy") && password.equals("123456")) {
return ResultVo.ok(1, "登录成功");
} else {
return ResultVo.error(-1, "登陆失败");
}
}
}
启用方法 在springboot2.7之前,都不用导入依赖, 依赖在我的博客上。升级版本就去导。
package com.qf.HomeWork.controller;
import com.qf.HomeWork.entity.HelloVo;
import com.qf.HomeWork.entity.User;
import com.qf.HomeWork.util.ResultVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import javax.validation.constraints.*;
@RestController
@RequestMapping("/p")
@Validated //开启基于注解的校验功能
public class PramcheckController {
//@Size(min=3,max=5,message = "长度应该在3-5之间")
/**
*@NotNull注解要求name只是不能为null,可以为空串
*/
@RequestMapping("/test1")
public ResultVo test1( @NotNull String name){
System.out.println(name);
return ResultVo.ok(1,name);
}
/**
*@NotEmpty注解要求name既不能为空串,也不能为null
*/
@RequestMapping("/test2")
public ResultVo test2( @NotEmpty String name){
System.out.println(name);
return ResultVo.ok(1,name);
}
/**
*@Email 邮箱验证
*/
@RequestMapping("/test3")
public ResultVo test3( @Email(message = "不合法邮箱") String name){
System.out.println(name);
return ResultVo.ok(1,name);
}
/**
*@Pattern 正则表达式验证
*/
@RequestMapping("/test4")
public ResultVo test4( @Pattern(message = "你的手机号输入不对",regexp = "^1(3[0-9]|4[579]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[89])\\d{8}$") String name){
System.out.println(name);
return ResultVo.ok(1,name);
}
/**
*@Valid 验证对象的注解
*/
@RequestMapping("/test5")
public ResultVo test5(@Valid HelloVo user){
System.out.println(user);
return ResultVo.ok(1,user);
}
}
在实体类里面可以,加注解校验,然后在方法上加 @Valid 就可以开启校验了
package com.qf.HomeWork.entity;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Data
public class HelloVo {
@NotNull
private Integer id;
// @NotNull // 需要该参数不能为null
@NotEmpty // 不可以为空串
@Size(min = 5,max = 100)
private String name;
@Email
private String email;
}
package com.qf.HomeWork.runner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class MyRunner implements ApplicationRunner {
@Value("${server.port}")
private Integer port;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("http://localhost:"+port);
}
}
导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
<version>2.2.9.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<version>2.2.9.RELEASEversion>
<optional>trueoptional>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>knife4j-spring-boot-starterartifactId>
<version>2.0.4version>
dependency>
dependencies>
在主启动类上面加上
@EnableSwagger2//开启swagger依赖
@EnableKnife4j//开启knife4j皮肤
然后写个配置类
package com.qianfeng.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Swagger基础配置类
* 此类相当于配置文件, 项目启动就立即自动加载此类
*
*/
@Configuration
public class SwaggerConfiguration {
@Bean
public Docket buildDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(buildApiInfo())
.select()
// 要扫描的API(Controller)基础包
.apis(RequestHandlerSelectors.basePackage("com.qianfeng.controller"))
.build();
}
private ApiInfo buildApiInfo() {
Contact contact = new Contact("千锋教育","http://www.baidu.com","[email protected]");
return new ApiInfoBuilder()
.title("千峰教育API文档")
.description("平台管理服务api")
.contact(contact)
.version("1.0.0")
.build();
}
}
加到IOC容器,即可使用
调用官网 小刀 http://localhost:8080/doc.html
swagger 访问地址:http://localhost:8080/swagger-ui.html
然后我把它写成了启动器
package com.qf.swagger.spring.boot.autoconfigure.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("com.qf.swagger")
public class SwaggerProperties {
//联系人的名字
private String contactName;
//联系人的网址
private String contactUrl;
//联系人的邮箱
private String email;
//文档的标题
private String title;
//项目的描述信息
private String description;
//项目的版本号
private String version;
//swagger扫描下的包
private String packageName;
public String getContactName() {
return contactName;
}
public void setContactName(String contactName) {
this.contactName = contactName;
}
public String getContactUrl() {
return contactUrl;
}
public void setContactUrl(String contactUrl) {
this.contactUrl = contactUrl;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
}
package com.qf.swagger.spring.boot.autoconfigure;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import com.qf.swagger.spring.boot.autoconfigure.properties.SwaggerProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2//开启swagger依赖
@EnableKnife4j//开启knife4j皮肤
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerAutoConfigure {
@Autowired
private SwaggerProperties swaggerProperties;
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(buildApiInfo())
.select()
// 要扫描的API(Controller)基础包
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getPackageName()))
.build();
}
private ApiInfo buildApiInfo() {
Contact contact = new Contact(swaggerProperties.getContactName(),swaggerProperties.getContactUrl(),swaggerProperties.getEmail());
return new ApiInfoBuilder()
.title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription())
.contact(contact)
.version(swaggerProperties.getVersion())
.build();//最后调用build方法返回ApiInfo对象
}
}
com:
qf:
swagger:
package-name: com.qf.HomeWork.controller
contact-name: 蒋铭基
contact-url: http://www.baidu.com
email: [email protected]
title: 蒋铭基的接口API文档
description: 这是蒋铭基项目的接口描述文档的描述信息。很棒!
version: 1.1.0
<dependency>
<groupId>com.qfgroupId>
<artifactId>swagger-spring-boot-startartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
导入依赖
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.2.6version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
yml配置数据源
#配置数据源
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 2001
url: jdbc:mysql://47.94.172.139:6789/lawer?useSSL=false&useUnicode=true&characterEncoding=utf8
type: com.alibaba.druid.pool.DruidDataSource
即可调用数据源 ,已经在IOC容器里面了 也可也使用JDBC模板,但是必须要导入 spring-boot-starter-jdbc依赖
package com.qf;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@SpringBootTest
class Spring05DataApplicationTests {
//数据源会自动装配,配置类数据源类型,会通过XXXproperties绑定的XXXAutoConfigure里的Bean加载到IOC容器里面,
// 当包生效,就会把数据源放入到IOC容器里。
@Autowired
private DataSource dataSource;
@Test
void contextLoads() throws SQLException {
System.out.println(dataSource.getClass());
//获取数据源链接
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
}
package com.qf.HomeWork.exhandler;
import com.qf.HomeWork.util.ResultVo;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice//全局异常处理器的注解,相当于增强通知
public class GlobalExHandler {
//底层不是AOP,就是调用了DispatcherServlet,拿到映射器处理器找到对应的Controller,应该是捕获到异常的时候,就会触发映射器找到这个方法,实现这个方法响应,一个数据给客户端
@ExceptionHandler(Exception.class)
public ResultVo handleEx(Exception e){
e.printStackTrace();
return ResultVo.error(-1,"出异常了,请与运维联系!");
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 这种方式也会覆盖掉默认的web静态资源目录
registry.addResourceHandler("/**").addResourceLocations("classpath:static/","classpath:templates/");
}
}
# 注意:这样配置会覆盖掉默认的web静态资源目录
spring.web.resources.static-locations=classpath:/templates
#日期格式json
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
package com.qf.HomeWork.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
//跟json,没关系,一般是表单提交查询字符串的时候,用这个,
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
//因为刚刚不是用springboot去接受的,用的是jackson来接收的,所以得加上这个注解,
//请求有过滤器,响应有响应头,纯文本响应头,json响应头。
//请求日期类型有 dateTimeFormat json有 JsonFormat 在 springboot配置文件已经配好了,在自动装配里会把配置信息放入Jackson对象,放到IOC容器里
//springboot这个底层也是用jackson接收,他在配置文件里写了,被注入IOC容器得jackson对象配置了注入日期格式的问题。
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")//会用就行,记住大概的原理,一查就知道了,不需要记得那么牢,就是格林威治时间与中国时区差8小时
private Date birthday;
private Integer status;
}
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.10version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.3.2version>
dependency>
导入依赖
#mybatis 的必要配置,配置mapperxml文件的位置 类路径包括导入所有jar包的类路径下的所有文件夹下的所有Mapper.xml为映射文件。
mybatis:
mapper-locations: classpath*:**/*Mapper.xml
#开启mybatis的sql日志。
logging:
level:
com.qf.HomeWork.mapper: debug
配置文件
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.2.5version>
dependency>
@Test
public void test(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
//分页
PageHelper.startPage(2,5);
List<Book> byPage = mapper.findByPage();
//分页对象,里面有各种上一页,下一页,总页数,什么的数据
PageInfo<Book> pageInfo = new PageInfo<>(byPage);
for (Book book : byPage) {
System.out.println(book);
}
System.out.println("---------------");
System.out.println(pageInfo);
System.out.println(pageInfo.getList());
}
导入依赖
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.2.6version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
#开启mybatis-plus的sql日志。
logging:
level:
com.qf.HomeWork.mapper: debug
通过继承BaseMapper<泛型> 来继承自动SQL的生成
package com.qf.MP2302.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qf.MP2302.entity.Category;
import java.util.List;
public interface CategoryMapper extends BaseMapper<Category> {
List<Category> findAll(int parentID);
}
@Transactional(rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED)//隔离级别,调整为读已提交
在方法上加上这个就能代理这个方法,或者加到类上,就能让类里所有的方法开启事务。
//定义在实体类里
/**
* mybatis-plus不允许下划线,他会有默认的命名策略,将驼峰命名映射到数据库的下划线的数据库名,绑定对应的值
* 如果不用驼峰命名,下划线,虽然能查出来条数,也会生成正确的sql,但是数据回显的时候,他会将数据库查询出来的,字段
* 映射成驼峰命名的map集合,但是在实体类里,它却是下划线,所以匹配不到属性,赋不上值,所以,传回来一个空对象,,如果有值,就创建对象,没值,就把空对象加入集合里,没有映射上去的话,就是ORM,从下划线映射成驼峰命名,这个策略,若
* 属性不是驼峰命名,则对应不上,就会返回一个空对象,把这个空对象加入集合,最后就会存在很多空对象的集合 !!!
* mybatis-plus加了@TableField(exist = false),这个就会,表示这个属性不存在字段在数据库当中,也不会映射,上去,不会报错
*/
@TableName("sys_user")//定义表名,加载类名上
@TableId(type = IdType.AUTO,value = "category_id")//定义主键,加载字段上
//INPUT 是自动填充NULL。然后数据库自增
//NONE是数字UUID,
//AUTO 主键自增 其他都懂
@TableField("category_name")//定义字段
@TableField(exist = false)//定义属性不在数据库字段里
@Version//乐观锁的版本号
@TableLogic//逻辑删除键 数据库表中的逻辑删除字段设置默认值为0(未删除)。
@Configuration
// 在mybatisplus的配置类上也可以添加注解扫描,启动类和配置类二选一,添加一处即可
// @MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
@Test
void select() {
Page<User> userPage = new Page<>(1,3);
//这里示范无条件查询,所以null
userPage= userDao.selectPage(userPage,null);
long total = userPage.getTotal();
System.out.println("总条数:"+total);
System.out.println("总页数:"+userPage.getPages());
System.out.println("当前页数据:"+userPage.getRecords());
}
分页查询,用map集合接收,map集合当实体类,key就是Select后面的字段,包括别名
@Test
void selectByPage() {
//ORM映射,这个问题解决了,就是SQL查出来的数据封装成Map集合
Page<Map<String,Object>> userPage = new Page<>(1,3);
userPage= userDao.selectMapsPage(userPage,null);
long total = userPage.getTotal();
System.out.println("总条数:"+total);
System.out.println("总页数:"+userPage.getPages());
System.out.println("当前页数据:"+userPage.getRecords());
}
在配置类:注册
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
乐观锁的例子
package com.qf.MP2302.service.impl;
import com.qf.MP2302.entity.Product;
import com.qf.MP2302.mapper.ProductMapper;
import com.qf.MP2302.service.ProductService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductMapper productMapper;
@Transactional(rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED)//隔离级别,调整为读已提交
@Override
public boolean modPrice(Long id, Integer deltaPrice) {
//1.根据id查询商品信息
Product product = productMapper.selectById(id);
Integer cunrrentPrice = product.getPrice();
Integer newPrice = cunrrentPrice - deltaPrice;
//2.修改数据库表
product.setPrice(newPrice);
int i = productMapper.updateById(product);
//3.乐观锁的补偿机制,如果出现i=0的情况,说明出现了并发冲突,重试
while (i==0){
Product productAgain=productMapper.selectById(id);
Integer againPrice = productAgain.getPrice();
int newPriceAgain = againPrice - deltaPrice;
productAgain.setPrice(newPriceAgain);
i=productMapper.updateById(productAgain);
}
return i==1;
}
}
导入依赖
<dependencies>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-freemarkerartifactId>
<version>2.2.9.RELEASEversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
dependencies>
通过主启动类,启动,来实现代码的自动生成
package com.qf.gen;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Gen {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false", "root", "2001")
// 全局配置
.globalConfig((scanner, builder) -> builder.author(scanner.apply("请输入作者名称?")).fileOverride().outputDir("F:/MPgen"))
// 包配置
.packageConfig((scanner, builder) -> builder.parent(scanner.apply("请输入包名?")).moduleName(scanner.apply("请输入模块名?")).pathInfo(Collections.singletonMap(OutputFile.xml, "F:/MPgen")))
// 策略配置
.strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
.controllerBuilder().enableRestStyle().enableHyphenStyle()
.entityBuilder().enableLombok().addTableFills(
new Column("create_time", FieldFill.INSERT)
).build())
/*
模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
.templateEngine(new BeetlTemplateEngine())
.templateEngine(new FreemarkerTemplateEngine())
*/
.templateEngine(new FreemarkerTemplateEngine())
.execute();
}
// 处理 all 情况
protected static List<String> getTables(String tables) {
return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
}
}