SpringBoot应用简单示例
- SpringBoot应用简单示例
- HelloWorld
- 搭建项目
- @ResponseBody的作用
- @ComponentScan排除扫描bean
- SpringBoot集成日志
- SpringBoot日志初始化原理
- 消息转换器
- 拦截器
- 过滤器
- 操作数据库
- Spring Data Jpa
- Druid数据源
- Mybatis-Plus
- 事务处理
- 操作缓存
- AOP
- 相关概念
- 栗子
- 定时任务
- @Scheduled
- Quartz
- Spring Boot Admin
- 参考资料
SpringBoot应用简单示例
HelloWorld
搭建项目
File -> new project 选择springboot项目初始化。
选择项目默认依赖。
在项目中建一个controller,代码如下:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* hello world测试类
* @author Alone
*/
@RestController
public class HelloController {
@RequestMapping("/hello")
public String Hello() {
return "Hello,world!";
}
}
输出结果:
@ResponseBody的作用
将方法的返回值,以特定的格式写入到response的body区域,进而将数据返回给客户端。当方法上面没有写ResponseBody,底层会将方法的返回值封装为ModelAndView对象。如果返回值是字符串,那么直接将字符串写到客户端;如果是一个对象,会将对象转化为json串,然后写到客户端。
@RequestMapping、@ResponseBody 等这些注解是干什么的? - 果真真的回答 - 知乎
前置知识-SpringMVC请求流程
DispatcherServlet#doDispatch
@ComponentScan排除扫描bean
SpringBoot集成日志
SpringBoot日志初始化原理
有个loggingApplicationListener的监听器,监听了spring的事件,读取了spring容器中的日志配置,进行了日志的初始化。
(springboot-actuator可以实现动态调整日志级别,待研究)
消息转换器
to be continue
拦截器
拦截器是一种动态拦截方法调用的机制。可以在指定方法前后执行预先设定的代码以及阻止方法调用。
拦截器的实现需要实现HandlerInterceptor
接口:
/**
* 拦截器测试
* @author Alone
*/
@Component
public class InterceptConfiguration implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...");
// 此处返回false导致后面不再执行
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
将拦截器添加入SpringMVC的配置类:
/**
* @author Alone
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private InterceptConfiguration interceptConfiguration;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptConfiguration);
}
}
默认是返回true。
HandlerInterceptor
中三个方法的作用:
preHandler(HttpServletRequest request, HttpServletResponse response, Object handler)
: 方法在请求处理之前调用,在这个方法中进行一些前置预处理或初始化操作,也可以决定是否终止请求。当该方法返回false时,后续的interceptor和controller都不会执行。拦截器可以注册多个,调用时依据声明顺序依次执行。
handler
参数本质上是一个方法对象,有了它就可以操作原始执行的方法。postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
: 在当前请求处理之后,DispatcherServlet进行视图渲染之前调用。此时可以对controller处理之后的modelAndView对象进行操作。afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)
: 该方法在整个请求结束后进行调用,主要用于清理资源。
多拦截器的执行顺序:
过滤器
to be continue
操作数据库
Spring Data Jpa
- 引入依赖 pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
配置文件application.yml:
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: update
datasource:
url: jdbc:mysql://localhost:3306/gotest?useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 我是密码
spring.jpa.hibernate.ddl-auto
属性的选项说明:
create
: 无论数据是否改变,每次hibernate
加载时都删除上一次生成的表create-drop
: 每次加载hibernate
时都根据实体类生成表,但是sessionFactory一关闭,表就自动删除。update
: 每次加载hibernate时根据model类会自动更新表的结构,不存在则新建。不会删除旧数据。validate
: 每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。none
: 不做任何操作
实体类:
package com.alone.simpleusage.database.datajpa.entity;
import lombok.Data;
import javax.persistence.*;
/**
* 学生实体类
* @Entity 表示这是一个实体类
* @Table 定义数据库表名,jpa在操作的时候会先去寻找这张表,没有这张表的话就创建
*
* @author Alone
*/
@Data
@Entity
@Table(name = "student")
public class Student {
/**
* @Id 表示这是主键
* @GeneratedValue 主键生成策略
* @Column 配置属性和数据库字段的对应
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer urid;
@Column(name = "code")
private String code;
@Column
private String name;
}
dao接口:
package com.alone.simpleusage.database.datajpa.dao;
import com.alone.simpleusage.database.datajpa.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentRepository extends JpaRepository<Student, Integer> {
}
运行测试:
@SpringBootTest
public class RepositoryTest {
@Autowired
private StudentRepository studentRepository;
@Test
public void testInsert() {
Student student = new Student();
student.setCode("1");
student.setName("顶不住了");
studentRepository.save(student);
}
}
运行结果:
Spring JPA实现的默认方法:
Spring jpa 动态查询:
public interface StudentRepository extends JpaRepository<Student, Integer>, JpaSpecificationExecutor<Student> {
}
@Test
public void testQuery() {
List<Student> userList = studentRepository.findAll(((root, criteriaQuery, criteriaBuilder) -> {
// 定义集合,用于存放动态查询条件
List<Predicate> predicateList = Lists.newArrayList();
predicateList.add(criteriaBuilder.like(root.get("code").as(String.class), "%1%"));
predicateList.add(criteriaBuilder.like(root.get("name").as(String.class), "%顶%"));
return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));
}));
userList.forEach(System.out::println);
}
输出结果:
多表联查:
to be continue
分页查询:
@Test
public void testPageQuery() {
// 构造查询条件
Specification<Student> spec = new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return null;
}
};
// 分页查询接口
PageRequest pageRequest = PageRequest.of(0, 1);
Page<Student> students = studentRepository.findAll(spec, pageRequest);
System.out.println("查询总页数:" + students.getTotalPages());
System.out.println("查询总记录数:" + students.getTotalElements());
System.out.println("数据集合列表:" + students.getContent());
}
结果:
排序查询:
@Test
public void testSortQuery() {
Sort sort = Sort.by(Sort.Direction.DESC, "urid");
Specification<Student> spec = new Specification<Student>() {
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return null;
}
};
List<Student> studentList = studentRepository.findAll(spec, sort);
for (Student student : studentList) {
System.out.println(student);
}
}
Druid数据源
- 添加依赖引入druid数据源:
<!-- spring jdbc 操作模版 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 引入druid数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.4</version>
</dependency>
- 编写配置文件:
spring:
datasource:
url: jdbc:mysql://localhost:3306/gotest?useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 密码
type: com.alibaba.druid.pool.DruidDataSource
- 编写配置bean:
/**
* Druid数据源配置类
* @author Alone
*/
@Configuration
public class DruidConfig {
/**
* 配置绑定
* @return
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druid() {
return new DruidDataSource();
}
}
此处的前缀prefix要和application.yml中的前缀对应,不然会报java.sql.SQLException: url not set
的异常。
且该注解一定要标在对应bean上。
- 测试获取数据源
@Test
public void testGetDruidDataBase() throws SQLException {
System.out.println(dataSource.getClass());
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
Mybatis-Plus
- 引入依赖:
<!-- mybatis-plus 依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
- 配置文件:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启sql语句打印
- 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
private Long managerId;
private LocalDateTime createTime;
}
此处简单说一下LocalDateTime相较于Date的优点:
- Date类型的打印出的日期可读性差
- Date使用
SimpleDateFormat
进行格式化,该对象线程不安全 - Date日期处理麻烦,
getYear()
getDay()
等方法均已被弃用
- 定义mapper接口
public interface UserMapper extends BaseMapper<User> {
}
- 启动类添加mapperscan注解
@SpringBootApplication
@MapperScan("com.alone.simpleusage.database.mpp")
public class SimpleusageApplication {
public static void main(String[] args) {
SpringApplication.run(SimpleusageApplication.class, args);
}
}
- 测试
@Test
public void testUserMapper() {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
User user = new User(6L, "test", 10, "123456@163.com", null, LocalDateTime.parse("2022-11-08 15:44:00", df));
userMapper.insert(user);
}
事务处理
【Java】Spring事务相关笔记
操作缓存
AOP
相关概念
栗子
springboot切面实现打印当前系统时间:
pom.xml:
<!-- aop依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
切面类:
package com.alone.simpleusage.aop.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
/**
* 切面类
* @author Alone
*/
@Aspect
@Component
@Slf4j
public class SysOutTimeAspect {
/**
* 切入点方法
*/
@Pointcut("execution(public * com.alone.simpleusage.aop.controller.*.*(..))")
public void printTime() {
}
/**
* 前置通知
* 这里的方法名和入参都不能写错,不然会进不去需要被增强的方法
* @param joinPoint
*/
@Before("printTime()")
public void doBefore(JoinPoint joinPoint) {
log.info("开始打印");
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
log.info(df.format(System.currentTimeMillis()));
}
}
测试类:
package com.alone.simpleusage.aop.controller;
import org.springframework.web.bind.annotation.*;
/**
* 切面测试controller
* @author Alone
*/
@RestController
@RequestMapping("/aoptest")
public class AopController {
@RequestMapping("/hello")
public String hello(@RequestParam(value = "name", required = false) String name) {
System.out.println("进入hello方法");
return "hello" + name;
}
}
结果:
定时任务
@Scheduled
Quartz
Spring Boot Admin
参考资料
- springboot动态调整日志级别
- 玩转 Spring Boot 系列案例源码
- 优雅的使用spring boot: 消息转换器的介绍与使用
- SpringBoot实现过滤器、拦截器与切片
- 黑马程序员2022新版SSM框架教程
- SpringBoot图文教程12—SpringData Jpa的基本使用
- Springboot 系列(九)使用 Spring JDBC 和 Druid 数据源监控
- mybatis plus 看这篇就够了,一发入魂
- 学会了MybatisPlus,代码开发效率提高了10倍!
- Spring Boot (五): Redis缓存使用姿势盘点
- Spring boot学习(六)Spring boot实现AOP记录操作日志
- SpringBoot—集成AOP详解(面向切面编程Aspect)