SpringBoot的主要功能如下:
- 起步依赖:SpringBoot以功能化的方式将需要的依赖进行组装,并且允许程序员以start的方式进行引入
- 默认配置:SpringBoot实现了大量依赖框架的默认配置项,程序员无须再进行自己配置
- 内置Tomcat:SpringBoot内置了一个tomcat,使用它开发的程序无需再进行tomcat部署,可直接运行
创建工程,导入依赖
注意: springboot工程要求必须去继承一个springboot提供的父工程,然后根据业务需要引入指定的starter
<!--父工程-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
</parent>
<dependencies>
<!--JDK11中没有的一些xml解析的依赖-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--springboot单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
</dependencies>
创建启动类
//注意启动类的位置,必须位于其他类的父包中
@SpringBootApplication
@MapperScan("com.itheima.mapper")//接口扫描
public class SpringBootDemoApplication {
public static void main(String[] args){
SpringApplication.run(SpringBootDemoApplication.class,args);
}
}
实体类
实体类解决时间格式问题
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Long id;
private String number;
private String userName;
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "Asia/Shanghai")
private Date birthday;
private String address;
}
先使用三层架构写法(面向接口编程)
表示层(web):主要接收前端发送的请求,并响应数据=======>controller
业务层(service): 负责处理具体的业务逻辑=======>service
持久层(dao): 负责对数据库进行增删改查操作========>dao 或 mapper
java文件的命名方式也是domain包的实体类名+对应层的后缀。
service还要创建对应的实现类在业务层Impl包下,名字可以Impl结尾。
比如: domain = User mapper = UserMapper
分别在你的每层上面加上与之对应的实例化注解
@Component
用于实例化对象,它支持一个value属性类定义bean在容器中的唯一标识
如果不写,默认值为类名的首字母小写
@Controller @Service @Repository
这三个注解的功能跟@Component类似,他们分别标注在不同的层上。
@RestController 标注在表示层的类上
@Service 标注在业务层的类上
@Mapper 标注在持久层的类上
推荐使用这三个,当一个类实在不好归属在这三个层上时,再使用@Component
在yaml文档里配置数据源、开启驼峰映射、日志等操作。
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/tlias
username: root
password: 1234
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#开启驼峰映射
map-underscore-to-camel-case: true
在dao层接口类写入CRUD方法,在Service层的接口和它实现类中写入CRUD,实现类的重写方法中
利用@Autowired依赖注入获取dao层接口类的对象达到调用方法的作用。
使用@Autowired依赖注入可以在实现类中获取IOC容器中的对象
@Autowired注解,默认是按照类型进行属性的赋值,如果存在多个相同类型的bean,就会报错
@Qualifier(实现类的name)跟@Autowired联合使用,标注在要赋值的属性上,代表在按照类型匹配的基础上,再按照指定名称匹配
@Primary标注在实现类上,表示当一个接口有多个实现的类时,默认使用哪个作为主实现
写controller类要遵守的一些约定
在写controller类的CRUD时候,类名上最好使用@RestController注解,为什么呢?
@RestController = @Controller + @ResponseBody
使用@Autowired注解,在你的controller类中获取service层对象,
然后方法满足Restful规范
保存 @postMapping /user
修改 @putMapping /user/id/1
删除 @DeleteMapping /user/id
查询所有 @GetDeleteMapping /user
查询一个 @GetDeleteMapping /user/id
方法的返回值,还要满足和前端看的懂的形式。
单独写一个类方法vo包下,作为返回的对象。
实现CRUD
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code;//响应码,1 代表成功; 0 代表失败
private String msg;//响应信息 描述字符串
private Object data;//返回的数据
//增删改 成功响应
public static Result success(){
return new Result(1,"success",null);
}
//查询 成功响应
public static Result success(Object data){
return new Result(1,"success",data);
}
//失败响应
public static Result error(String msg){
return new Result(0,msg,null);
}
}
Controller类
@RestController
public class StudentController {
@Autowired
private StudentService studentService;
//查询全部
@GetMapping("/student")
public Result findAll(){
List<Student> studentList = studentService.findAll();
return Result.success(studentList);
}
//删除
@DeleteMapping("/student/{id}")
public Result deleteById(@PathVariable("id") Long id){
studentService.deleteById(id);
return Result.success();
}
//查找一个
@GetMapping("/student/{id}")
public Result findById(@PathVariable("id") Long id){
Student byId = studentService.findById(id);
return Result.success(byId);
}
//修改
@PutMapping("/student")
public Result updateById(@RequestBody Student student){
studentService.updateById(student);
return Result.success();
}
//增加
@PostMapping("/student")
public Result add(@RequestBody Student student){
studentService.add(student);
return Result.success();
}
}
404 路径问题
405 请求方式错误
400 请求参数错误
500 后台错误
200 成功
还是要根据实际情况写。
无条件分页查询
-- 总结: 查询第page页,每页pageSize条 select * from emp limit (page-1)*pageSize,pageSize;
添加依赖
<!--mybatis分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
示例代码:
PageBean类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean<T> {
//数据的总数
//private Long total;
private Long total;
//每页返回的数据
//private List<T> rows;
private List<T> rows;
}
dao层
@Select("select * from emp")
public List<Emp> list();
service实现类
@Override
public PageBean<Emp> findByPage(Integer page, Integer pageSize) {
//1 设置分页参数
PageHelper.startPage(page,pageSize);
//2 执行查询
List<Emp> empList = empMapper.list();
//3 查询结果转Page对象
Page<Emp> p = (Page<Emp>) empList;
//4 封装对象查询
return new PageBean<Emp>(p.getTotal(),p.getResult());
controller层
@GetMapping("/emps")
public Result findByPage(
//分页查询的页码,如果未指定,默认为1
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize
){
PageBean<Emp> pageBean = empService.findByPage(page,pageSize);
return Result.success(pageBean);
}
带条件分页查询
dao层xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
<select id="findList3" resultType="com.itheima.pojo.Emp">
select * from emp
<where>
<if test="name != null and name != ''">
and name like concat("%",#{name},"%")
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
</select>
</mapper>
SpringAOP优化代码
AOP
AOP是一种思想,把核心和非核心的业务代码进行分离,解耦合。
还能再原有的基础上进行额外的操作。
如果有接口,就采用jdk动态代理
如果没接口,就采用cglib的方式
Spring AOP(面向切面编程)
Spring Aop 底层基于jdk动态代理和cglib动态代理。
当我们需要在核心代码增加一个非核心功能时,可以单独给这个非核心功能写一个增强类里,并且加上@Aspect//切面注解
在增强类中写一个切点(切点表达式)----->\作用:可以标注在要增强的方法上面。
//切点表达式
//@Pointcut("execution( com.itheima.service.Impl..(..))")
@Pointcut("@annotation(com.itheima.annotation.LogAnno)")//自定义切点
public void pt(){}
AOP获取目标对象
@Aspect
@Component
public class MyAop {
//切点:controller所有方法
@Pointcut("execution (* com.itheima.controller.*.*(..))")
public void myPointcut(){
}
@Around("myPointcut()")
public Object m1(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs();
//被切方法只有一个参数
if (args.length==1 && args[0] instanceof Emp){
Emp emp = (Emp) args[0];
emp.setUpdateTime(LocalDateTime.now());
}
Object object = pjp.proceed();
return object;
}
}
AOP使用日志技术统计方法前后所费的时间
日志在yml文件如何配置?
# 设置 输出
# debug debug info warn error
# info info warn error
# warn warn error
# error error
logging:
level: #指定每个包下来要记录的日志级别
com.itheima:info
file: #制定日志输出路径文件
name: D:\springboot.log
@Aspect
@Component
@Slf4j
public class LogAop {
//切点:controller所有方法
@Pointcut("execution(* com.itheima.controller.*.*(..))")
public void logAop(){}
@Around("logAop()")
public Object m1(ProceedingJoinPoint pjp) throws Throwable {
Object obj = null;
long start = System.currentTimeMillis();
String format1 = new SimpleDateFormat("HH:mm:ss").format(start);
log.info(format1);
obj=pjp.proceed();
long end = System.currentTimeMillis();
String format2 = new SimpleDateFormat("HH:mm:ss").format(end);
log.info(format2);
log.info(String.valueOf(end-start)+"ms");
return obj;
}
}