# SpringBootDemo **Repository Path**: alexl2/spring-boot-demo ## Basic Information - **Project Name**: SpringBootDemo - **Description**: Spring Boot 学习笔记 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-06-06 - **Last Updated**: 2025-06-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Spring Boot 学习笔记 ## 1. HelloWolrd 从 [Spring Initializr](https://start.spring.io/) 官网生成项目包,选择 web模块。 然后,新建 `HelloController` ```java @RestController public class HelloController { @RequestMapping("/hello") @ResponseBody public String hello() { return "Hello World!"; } } ``` 在 `DemoApplication` 类中,运行程序:`Run DemoApplication.main()`,在浏览器地址栏输入:`http://localhost:8080/hello` ,就可以看到结果:`Hello World!`。 ## 2. 日志 logback.xml 配置 参考:[logback的使用和logback.xml详解](https://www.cnblogs.com/warking/p/5710303.html) 日志输出级别: 根据Level的级别,优先级大的优先输出,优先级从大到小为: `ERROR>WARN>INFO>DEBUG>TRACE` ``` %d{yyyy-MM-dd'T'HH:mm:ss.SSS zXXX} 表示显示带时区的时间格式,如: 022-02-25T22:18:54.373 CST+08:00 [main] INFO com.example.demo.DemoApplication:61 - xxx ``` logback-spring.xml的例子: ```xml %d{yyyy-MM-dd'T'HH:mm:ss.SSS zXXX} [%thread] %-5level %logger{50}:%L - %msg%n ${LOG_HOME}/${PROJECT_NAME}/springbootdemo.log ${LOG_HOME}/${PROJECT_NAME}/springbootdemo.%d{yyyy-MM-dd}.log 15 %d{yyyy-MM-dd'T'HH:mm:ss.SSS zXXX} [%thread] %-5level %logger{50}:%L - %msg%n 50MB ``` 访问时,日志输出为: ```shell 2022-02-25T22:32:49.434 CST+08:00 [http-nio-8888-exec-1] INFO com.example.demo.service.impl.HelloServiceImpl:27 - info Hello null 2022-02-25T22:32:49.434 CST+08:00 [http-nio-8888-exec-1] WARN com.example.demo.service.impl.HelloServiceImpl:28 - warn Hello null 2022-02-25T22:32:49.435 CST+08:00 [http-nio-8888-exec-1] ERROR com.example.demo.service.impl.HelloServiceImpl:29 - error Hello null ``` ## 3. 返回 Json 串 使用 `@RestController`: ```java @RestController @RequestMapping("/v1/book") public class BookController { @RequestMapping(value = "/books", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") public List test() { List books = new ArrayList<>(); Book b1 = new Book(); b1.setName("数学之美"); b1.setPublisher("人民邮电出版社"); b1.setAuther("吴军"); Book b2 = new Book(); b2.setName("重构 改善既有代码的设计"); b2.setPublisher("人民邮电出版社"); b2.setAuther("Martin Fowler"); Book b3 = new Book(); b3.setName("机器学习实战"); b3.setPublisher("人民邮电出版社"); b3.setAuther("Peter Harrington"); Book b4 = new Book(); b4.setName("Effective Java中文版"); b4.setPublisher("机械工业出版社"); b4.setAuther("Joshua Bloch"); books.add(b1); books.add(b2); books.add(b3); books.add(b4); return books; } } ``` 使用 curl 访问: ```shell 192:SpringBootDemo youngbear$ curl http://localhost:8080/v1/book/books -X POST [{"name":"数学之美","publisher":"人民邮电出版社","author":"吴军"},{"name":"重构 改善既有代码的设计","publisher":"人民邮电出版社","author":"Martin Fowler"},{"name":"机器学习实战","publisher":"人民邮电出版社","author":"Peter Harrington"},{"name":"Effective Java中文版","publisher":"机械工业出版社","author":"Joshua Bloch"}] ``` ## 5. 返回统一的json格式 ### 5.1 创建返回对象泛型类 统一对象类: `ResultVo.java` ```java import lombok.Data; @Data public class ResultVo { /** * 错误码 */ private Integer code; /** * 提示信息 */ private String msg; /** * 数据 */ private Result result; } ``` 其中,`Result`的定义为: `Result.java` ```java import lombok.Data; import java.util.List; @Data public class Result { /** * 数据总数 */ private Integer total; /** * 当前页数据 */ private List data; } ``` ### 5.2 创建异常类 错误定义枚举:`ErrorEnum.java` ```java package com.example.demo.infrastructure.enums; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-04-30 22:35 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description 错误定义:错误码及错误信息 */ public enum ErrorEnum { UNKNOWN_ERROR(-1, "unknown error."), HTTP_REQUEST_ERROR(9999, "http request error"), BOOK_NAME_NULL_ERROR(10001, "book name is null."), HELLO_NAME_NULL_ERROR(20001, "hi name is null."); final Integer errorCode; final String errorMessage; ErrorEnum(Integer errorCode, String errorMessage) { this.errorCode = errorCode; this.errorMessage = errorMessage; } public Integer getErrorCode() { return errorCode; } public String getErrorMessage() { return errorMessage; } } ``` 异常类:`DemoException.java` ```java package com.example.demo.infrastructure.exception; import com.example.demo.infrastructure.enums.ErrorEnum; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-04-30 22:31 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description 统一异常 */ public class DemoException extends RuntimeException { private static final long serialVersionUID = 1905532578117424643L; private final ErrorEnum errorEnum; public DemoException(ErrorEnum errorEnum) { this.errorEnum = errorEnum; } public DemoException(Throwable cause, ErrorEnum errorEnum) { super(cause); this.errorEnum = errorEnum; } public ErrorEnum getErrorEnum() { return errorEnum; } } ``` ### 5.3 创建工具类 创建工具类 `ResultUtils.java` ,进行封装返回成功信息,异常信息。 ```java package com.example.demo.infrastructure.utils; import com.example.demo.infrastructure.entity.Result; import com.example.demo.infrastructure.entity.ResultVo; import com.example.demo.infrastructure.enums.ErrorEnum; import com.example.demo.infrastructure.exception.DemoException; import java.util.ArrayList; import java.util.List; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-04-30 22:19 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ public class ResultVoUtils { /** * 成功返回 * * @param data 返回数据 * @param 数据类型 * @return 统一的返回值 */ public static ResultVo success(T data) { ResultVo resultVo = new ResultVo<>(); resultVo.setCode(Result.SUCCESS_CODE); resultVo.setMsg(Result.SUCCESS_MESSAGE); Result result = new Result<>(); if (data != null) { List dataList = new ArrayList<>(1); dataList.add(data); result.setTotal(1); result.setData(dataList); } else { result.setTotal(0); } resultVo.setResult(result); return resultVo; } public static ResultVo success(List dataList) { ResultVo resultVo = new ResultVo<>(); resultVo.setCode(Result.SUCCESS_CODE); resultVo.setMsg(Result.SUCCESS_MESSAGE); Result result = new Result<>(); if (dataList != null && dataList.size() > 0) { result.setTotal(dataList.size()); result.setData(dataList); } else { result.setTotal(0); } resultVo.setResult(result); return resultVo; } /** * 指定total,返回数据,用于分页场景 * * @param total 总数量 * @param dataList 当前数据 * @param 泛型参数 * @return resultVo */ public static ResultVo success(int total, List dataList) { ResultVo resultVo = success(dataList); resultVo.getResult().setTotal(total); return resultVo; } /** * 异常返回 * * @param demoException * @param * @return */ public static ResultVo error(DemoException demoException) { ResultVo resultVo = new ResultVo<>(); resultVo.setCode(demoException.getErrorEnum().getErrorCode()); resultVo.setMsg(demoException.getErrorEnum().getErrorMessage()); return resultVo; } /** * 异常返回 * * @param errorEnum * @param * @return */ public static ResultVo error(ErrorEnum errorEnum) { ResultVo resultVo = new ResultVo<>(); resultVo.setCode(errorEnum.getErrorCode()); resultVo.setMsg(errorEnum.getErrorMessage()); return resultVo; } } ``` ### 5.4 实践 以 `BookController` 为例,进行正常返回对象,正常返回数组,异常返回。 ```java package com.example.demo.api.controller; import com.example.demo.application.configuration.event.BookEvent; import com.example.demo.domain.entity.Book; import com.example.demo.infrastructure.entity.ResultVo; import com.example.demo.infrastructure.exception.DemoException; import com.example.demo.application.service.IBookService; import com.example.demo.infrastructure.utils.ResultVoUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; /** * @author youngbear * @email youngbear@aliyun.com * @date 2018/12/10 23:07 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ @RestController @RequestMapping(value = "/v1/book", produces = MediaType.APPLICATION_JSON_VALUE) public class BookController { @Autowired private IBookService bookService; @Resource private ApplicationContext applicationContext; @RequestMapping(value = "/book-list", method = RequestMethod.POST) public ResultVo bookList() { try { List books = bookService.bookList(); return ResultVoUtils.success(books); } catch (DemoException demoException) { return ResultVoUtils.error(demoException); } } @RequestMapping(value = "one-book", method = RequestMethod.POST) public ResultVo oneBook(@RequestBody Book book) { try { Book book1 = bookService.oneBook(book.getName(), book.getAuthor(), book.getPublisher()); BookEvent event = new BookEvent("BookEvent001"); event.setBook(book1); applicationContext.publishEvent(event); return ResultVoUtils.success(book1); } catch (DemoException demoException) { return ResultVoUtils.error(demoException); } } } ``` **对应`IService`文件:`IBookService.java`** ```java package com.example.demo.application.service; import com.example.demo.domain.entity.Book; import java.util.List; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-04-30 23:01 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ public interface IBookService { /** * 返回测试列表 * * @return */ List bookList(); /** * 构造一个书的对象 * * @param name * @param author * @param publisher * @return */ Book oneBook(String name, String author, String publisher); } ``` **Service实现类:`BookServiceImpl.java`** ```java package com.example.demo.application.service.impl; import com.example.demo.application.service.IBookService; import com.example.demo.domain.entity.Book; import com.example.demo.infrastructure.exception.DemoException; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import static com.example.demo.infrastructure.enums.ErrorEnum.BOOK_NAME_NULL_ERROR; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-04-30 23:05 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ @Service public class BookServiceImpl implements IBookService { @Override public List bookList() { List books = new ArrayList<>(); Book b1 = new Book(); b1.setName("数学之美"); b1.setPublisher("人民邮电出版社"); b1.setAuthor("吴军"); Book b2 = new Book(); b2.setName("重构 改善既有代码的设计"); b2.setPublisher("人民邮电出版社"); b2.setAuthor("Martin Fowler"); Book b3 = new Book(); b3.setName("机器学习实战"); b3.setPublisher("人民邮电出版社"); b3.setAuthor("Peter Harrington"); Book b4 = new Book(); b4.setName("Effective Java中文版"); b4.setPublisher("机械工业出版社"); b4.setAuthor("Joshua Bloch"); books.add(b1); books.add(b2); books.add(b3); books.add(b4); return books; } @Override public Book oneBook(String name, String author, String publisher) { if (null == name) { throw new DemoException(BOOK_NAME_NULL_ERROR); } Book book = new Book(); book.setName(name); book.setAuthor(author); book.setPublisher(publisher); return book; } } ``` #### 1. 获取列表 **请求:** ```shell curl -X POST "http://localhost:8080/v1/book/book-list" -H "accept: application/json;charset=UTF-8" ``` **对应返回值:** ```json { "code": 0, "msg": "request successful.", "result": { "total": 4, "data": [{ "name": "数学之美", "publisher": "人民邮电出版社", "author": "吴军" }, { "name": "重构 改善既有代码的设计", "publisher": "人民邮电出版社", "author": "Martin Fowler" }, { "name": "机器学习实战", "publisher": "人民邮电出版社", "author": "Peter Harrington" }, { "name": "Effective Java中文版", "publisher": "机械工业出版社", "author": "Joshua Bloch" }] } } ``` #### 2. 生成单个对象 **请求:** ```shell curl --location --request POST 'http://localhost:8888/v1/book/one-book' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": "机器学习实战", "publisher": "人民邮电出版社", "author": "Peter Harrington" }' ``` **返回结果:** ```json { "code": 0, "msg": "request successful.", "result": { "total": 1, "data": [ { "name": "机器学习实战", "publisher": "人民邮电出版社", "author": "Peter Harrington" } ] } } ``` #### 3. 返回异常信息: **请求:** ```shell curl --location --request POST 'http://localhost:8888/v1/book/one-book' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": null, "publisher": "人民邮电出版社", "author": "Peter Harrington" }' ``` **返回结果:** ```json { "code": 10001, "msg": "book name is null.", "result": null } ``` 用postman请求也可以实现同样的效果。具体可参考源代码。 ## 6. 处理全局异常 使用注解 `@RestControllerAdvice`,处理全局异常,在请求发生异常时,会通过该类进行处理: ```java package com.example.demo.application.configuration; import com.example.demo.infrastructure.entity.ResultVo; import com.example.demo.infrastructure.enums.ErrorEnum; import com.example.demo.infrastructure.exception.DemoException; import com.example.demo.infrastructure.utils.ResultVoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-05-04 21:53 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description 全局异常处理 */ @RestControllerAdvice public class GlobalExceptionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class); // 未知异常 @ExceptionHandler(value = Exception.class) public ResultVo defaultErrorHandler(Exception e) { LOGGER.error(e.getMessage(), e); return ResultVoUtils.error(ErrorEnum.UNKNOWN_ERROR); } // 自定义的异常 @ExceptionHandler(value = DemoException.class) public ResultVo errorHandler(DemoException e) { LOGGER.error(e.getMessage(), e); return ResultVoUtils.error(e.getErrorEnum()); } } ``` ## 7. 多环境配置 在 `src/main/resources` 下新建文件: ```shell application.yml application-dev.yml application-test.yml application-prod.yml ``` 其中,`application.yml` 用来指定具体使用哪个配置文件,其内容为: ```yaml spring: profiles: active: test ``` 则表示是使用的为 `application-test.yml`。 dev,test,prod分别表示开发,测试,生产环境。在实际的工作中,部署时使用脚本动态替换application.yml的active的值则可以做到多环境的部署。 可以在不同的环境下,配置不同的端口,数据库,日志等。 ## 8. 集成数据库 ### 8.1 添加依赖 ```xml mysql mysql-connector-java ${mysql.version} org.mybatis.spring.boot mybatis-spring-boot-starter ${mybatis.version} ``` ### 8.2 添加数据库配置 ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/springbootdemo username: bearyang password: 123456 mybatis: mapper-locations: classpath:mapper/*.xml ``` ### 8.3 实现java代码 首先创建数据库相关信息: ```mysql DROP TABLE IF EXISTS EMPLOYEE; -- create table CREATE TABLE EMPLOYEE ( ID INT UNSIGNED AUTO_INCREMENT, NAME VARCHAR(100) NOT NULL, HIRE_DATE BIGINT, SALARY DECIMAL(10,2), DEPT_NO INT(2), PRIMARY KEY (ID) ); -- 2010-09-14 00:00:00 INSERT INTO EMPLOYEE (NAME, HIRE_DATE, SALARY, DEPT_NO) VALUES ('小杨', 1284393600000, 8000.0, '06'); -- 2010-09-15 00:00:00 INSERT INTO EMPLOYEE (NAME, HIRE_DATE, SALARY, DEPT_NO) VALUES ('小张', 1284480000000, 9000.0, '05'); -- 2014-09-01 00:00:00 INSERT INTO EMPLOYEE (NAME, HIRE_DATE, SALARY, DEPT_NO) VALUES ('小孙', 1409500800000, 12000.0, '05'); -- 2014-09-02 00:00:00 INSERT INTO EMPLOYEE (NAME, HIRE_DATE, SALARY, DEPT_NO) VALUES ('小雷', 1409587200000, 12000.0, '05'); ``` #### 8.3.1 实体类 ```java package com.example.demo.entity; public class Employee { private Integer id; private String name; private String hireDate; private Float salary; private Integer deptNo; // 省略 getter and setter } ``` #### 8.3.2 DAO代码 java 代码: ```java package com.example.demo.domain.repository.dao; import com.example.demo.domain.entity.EmployeeVo; import org.apache.ibatis.annotations.Mapper; import java.util.List; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-07-21 18:21 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ @Mapper public interface IEmployeeDao { Integer add(EmployeeVo employeeVo); Integer delete(Integer id); void update(EmployeeVo employeeVo); EmployeeVo findEmployeeById(Integer id); List selectAll(); } ``` 对应xml: ```xml INSERT INTO EMPLOYEE (ID, NAME, HIRE_DATE, SALARY, DEPT_NO) VALUES (#{id}, #{name}, #{hireDate}, #{salary}, #{deptNo}) DELETE FROM EMPLOYEE WHERE ID = #{id} UPDATE EMPLOYEE SET NAME=#{name}, HIRE_DATE=#{hireDate}, SALARY=#{salary}, DEPT_NO=#{deptNo} WHERE ID = #{id} ``` 其中,名称为EmployeeResultMap的resultMap,作用是将数据库表的字段和java实体类的属性映射起来,在下边的查询语句中,可以直接使用resultMap="xxx",即可实现返回结果为实体类的类型。 #### 8.3.2 接口相关代码 IService: ```java package com.example.demo.application.service; import com.example.demo.domain.entity.EmployeeVo; import java.util.List; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-07-21 18:44 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ public interface IEmployeeService { /** * 添加一个 Employee * * @param employeeVo * @return 1-添加成功 */ Integer addEmployee(EmployeeVo employeeVo); /** * 根据 id 删除一个 Employee * * @param id * @return 1-删除成功 */ Integer deleteEmployee(Integer id); /** * 更新一个 Employee * * @param employeeVo * @return 更新成功后的结果 */ EmployeeVo updateEmployee(EmployeeVo employeeVo); /** * 根据 id 查询 Employee * * @param id * @return */ EmployeeVo queryEmployee(Integer id); /** * 查询所有 Employee * * @return */ List selectAll(); } ``` ServiceImpl: ```java package com.example.demo.application.service.impl; import com.example.demo.domain.repository.dao.IEmployeeDao; import com.example.demo.domain.entity.EmployeeVo; import com.example.demo.application.service.IEmployeeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-07-21 18:44 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ @Service public class EmployeeServiceImpl implements IEmployeeService { @Autowired private IEmployeeDao employeeDao; @Override public Integer addEmployee(EmployeeVo employeeVo) { return employeeDao.add(employeeVo); } @Override public Integer deleteEmployee(Integer id) { return employeeDao.delete(id); } @Override public EmployeeVo updateEmployee(EmployeeVo employeeVo) { employeeDao.update(employeeVo); return employeeDao.findEmployeeById(employeeVo.getId()); } @Override public EmployeeVo queryEmployee(Integer id) { return employeeDao.findEmployeeById(id); } @Override public List selectAll() { return employeeDao.selectAll(); } } ``` Controller: ```java package com.example.demo.api.controller; import com.example.demo.domain.entity.EmployeeVo; import com.example.demo.infrastructure.entity.ResultVo; import com.example.demo.infrastructure.exception.DemoException; import com.example.demo.application.service.IEmployeeService; import com.example.demo.infrastructure.utils.ResultVoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; /** * @author youngbear * @email youngbear@aliyun.com * @date 2019-07-21 18:43 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ @RestController @RequestMapping(value = "employee", produces = MediaType.APPLICATION_JSON_VALUE) public class EmployeeController { private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeController.class); @Resource private IEmployeeService employeeService; @RequestMapping(value = "/add", method = RequestMethod.POST) public ResultVo add(HttpServletRequest request, @RequestBody EmployeeVo employeeVo) { try { String userAccount = request.getHeader("X-USER-ACCOUNT"); LOGGER.info("userAccount: {}", userAccount); return ResultVoUtils.success(employeeService.addEmployee(employeeVo)); } catch (DemoException demoException) { return ResultVoUtils.error(demoException); } } @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) public ResultVo deleteById(@PathVariable("id") Integer id) { try { return ResultVoUtils.success(employeeService.deleteEmployee(id)); } catch (DemoException demoException) { return ResultVoUtils.error(demoException); } } @RequestMapping(value = "/update", method = RequestMethod.POST) public ResultVo updateEmployee(@RequestBody EmployeeVo employeeVo) { try { return ResultVoUtils.success(employeeService.updateEmployee(employeeVo)); } catch (DemoException demoException) { return ResultVoUtils.error(demoException); } } @RequestMapping(value = "/query/{id}", method = RequestMethod.GET) public ResultVo queryById(@PathVariable("id") Integer id) { try { return ResultVoUtils.success(employeeService.queryEmployee(id)); } catch (DemoException demoException) { return ResultVoUtils.error(demoException); } } @RequestMapping(value = "/queryAll", method = RequestMethod.GET) public ResultVo queryAll() { try { return ResultVoUtils.success(employeeService.selectAll()); } catch (DemoException demoException) { return ResultVoUtils.error(demoException); } } } ``` ### 8.4 运行结果 get请求:`http://localhost:8888/employee/query/3` 返回结果: ```json { "code": 0, "msg": "request successful.", "result": { "total": 1, "data": [ { "id": 3, "name": "小孙", "hireDate": 1409500800000, "salary": 12000.0, "deptNo": 5, "hireDateFormat": "2014-09-01" } ] } } ``` ### 8.5 日志配置显示sql日志 在 `logback-spring.xml` 中配置: ```xml ``` 其中,`com.example.demo.dao` 表示dao代码所在目录。 这样,我们就可以看到sql执行的日志了,如上边请求的日志为: ``` 2019-07-21 19:14:21.297 [http-nio-8888-exec-2] DEBUG com.example.demo.dao.IEmployeeDao.findEmployeeById - ==> Preparing: SELECT ID, NAME, HIRE_DATE, SALARY, DEPT_NO FROM EMPLOYEE WHERE ID = ? 2019-07-21 19:14:21.349 [http-nio-8888-exec-2] DEBUG com.example.demo.dao.IEmployeeDao.findEmployeeById - ==> Parameters: 2(Integer) 2019-07-21 19:14:21.423 [http-nio-8888-exec-2] DEBUG com.example.demo.dao.IEmployeeDao.findEmployeeById - <== Total: 1 ``` ## 9. 集成Redis ### Redis 基础 #### 1. Redis 简介 Redis 全称: REmote DIctionary Server,即远程字典服务。 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可以持久化的日志型、Key-Value型数据库。 #### 2. redis安装 ##### 2.1 windows下安装 参考:https://www.runoob.com/redis/redis-install.html 下载地址:https://github.com/tporadowski/redis/releases 将 `Redis-x64-5.0.14.1.zip` 解压后,把该路径添加到环境变量,打开命令行,就可以运行。 ```shell # 指定配置文件启动 redis-server redis.windows.conf # 连接 redis-cli -h 127.0.0.1 -p 6379 # 设置并查看 127.0.0.1:6379> set nametest valuetest123 OK 127.0.0.1:6379> get nametest "valuetest123" ``` windows下查看并删除redis进程: ```shell # 根据端口查看 netstat -ano | findstr 6379 # 根据进程名查看 tasklist | findstr redis # 杀掉进程 taskkill -pid <进程号> -f -t ``` #### 3. 集成springboot ##### 3.1 添加pom依赖 ```xml org.springframework.boot spring-boot-starter-data-redis ``` ##### 3.2 配置文件 ``` spring: redis: # Redis数据库索引(默认为0) database: 1 # Redis本地服务器地址,默认为127.0.0.1 host: 127.0.0.1 # Redis服务器端口,默认为6379.若有改动按改动后的来 port: 6379 #Redis服务器连接密码,默认为空,若有设置按设置的来 password: jedis: pool: # 连接池最大连接数,若为负数则表示没有任何限制 max-active: 8 # 连接池最大阻塞等待时间,若为负数则表示没有任何限制 max-wait: -1 # 连接池中的最大空闲连接 max-idle: 8 ``` ##### 3.3 添加测试代码 ```java package com.example.demo.api.controller; import com.example.demo.infrastructure.entity.ResultVo; import com.example.demo.infrastructure.utils.ResultVoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; /** * @author youngbear * @email youngbear@aliyun.com * @date 2022/5/9 23:28 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description redis基础 */ @RestController @RequestMapping(value = "redis", produces = MediaType.APPLICATION_JSON_VALUE) public class RedisController { private static final Logger LOGGER = LoggerFactory.getLogger(HelloController.class); @Autowired private StringRedisTemplate redisTemplate; @RequestMapping(value = "/setString", method = RequestMethod.POST) public ResultVo setString(@RequestParam(required = true) String key, @RequestParam(required = true) String value) { redisTemplate.opsForValue().set(key, value); // 设置过期时间为1小时 redisTemplate.expire(key, 3600L, TimeUnit.SECONDS); return ResultVoUtils.success("set successful."); } @RequestMapping(value = "/getString", method = RequestMethod.GET) public ResultVo getString(@RequestParam(required = true) String key) { String value = redisTemplate.opsForValue().get(key); Long expire = redisTemplate.getExpire(key); LOGGER.info("value: {}, expire: {}", value, expire); return ResultVoUtils.success("value: " + value + ", expire: " + expire); } } ``` 访问查看效果: ```shell # 设置 curl -X POST "http://localhost:8888/redis/setString?key=name1&value=value1" -H "accept: application/json" { "code": 0, "msg": "request successful.", "resultVo": { "total": 1, "data": [ "set successful." ] } } # 查看 curl -X GET "http://localhost:8888/redis/getString?key=name1" -H "accept: application/json" { "code": 0, "msg": "request successful.", "resultVo": { "total": 1, "data": [ "value: value1, expire: 3580" ] } } ``` #### todo ##### 1. redis基础 ##### 2. redis常用命令 ##### 3. springboot集成redis常用api ## 10. RestTemplate工具类 RestTemplateUtils工具类代码: ```java package com.example.demo.infrastructure.utils; import com.example.demo.infrastructure.enums.ErrorEnum; import com.example.demo.infrastructure.exception.DemoException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; /** * Http请求工具类 * * @author youngbear * @email youngbear@aliyun.com * @date 2022/8/7 23:32 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ @Component public class RestTemplateUtils { private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateUtils.class); @Resource private RestTemplate restTemplate; /** * http get 请求 * * @param url url * @param responseType response类型 * @param 类型参数 * @return response body */ public T get(String url, ParameterizedTypeReference responseType) { return http(url, HttpMethod.GET, null, responseType); } /** * http post 请求 * * @param url url * @param request 请求体 * @param responseType response类型 * @param 类型参数 * @return response body */ public T post(String url, Object request, ParameterizedTypeReference responseType) { return http(url, HttpMethod.POST, request, responseType); } /** * http 请求 * * @param url url * @param httpMethod method * @param request request * @param responseType response类型 * @param 类型参数 * @return response body */ public T http(String url, HttpMethod httpMethod, Object request, ParameterizedTypeReference responseType) { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); HttpEntity requestData = new HttpEntity<>(request, httpHeaders); ResponseEntity responseEntity; try { responseEntity = restTemplate.exchange(url, httpMethod, requestData, responseType); } catch (RestClientException e) { LOGGER.error("RestClientException when exchange", e); throw new DemoException(e, ErrorEnum.HTTP_REQUEST_ERROR); } if (responseEntity.getStatusCode() != HttpStatus.OK) { LOGGER.error("http request has response but status is not ok"); throw new DemoException(ErrorEnum.HTTP_REQUEST_ERROR); } T body = responseEntity.getBody(); if (body == null) { LOGGER.error("http request has response but response body is null"); throw new DemoException(ErrorEnum.HTTP_REQUEST_ERROR); } return body; } } ``` 验证: ```java package com.example.demo.api.controller; import com.example.demo.domain.entity.Book; import com.example.demo.domain.entity.EmployeeVo; import com.example.demo.infrastructure.entity.ResultVo; import com.example.demo.infrastructure.exception.DemoException; import com.example.demo.application.service.IHelloService; import com.example.demo.infrastructure.utils.RestTemplateUtils; import com.example.demo.infrastructure.utils.ResultVoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author youngbear * @email youngbear@aliyun.com * @date 2018/11/28 21:55 * @blog https://blog.csdn.net/next_second * @github https://github.com/YoungBear * @description */ @RestController @RequestMapping(value = "hello", produces = MediaType.APPLICATION_JSON_VALUE) public class HelloController { private static final Logger LOGGER = LoggerFactory.getLogger(HelloController.class); @Autowired private IHelloService helloService; @Resource private RestTemplateUtils restTemplateUtils; @RequestMapping(value = "/hi", method = RequestMethod.GET) public ResultVo hi(@RequestParam(required = false) String name) { try { String hi = helloService.hi(name); return ResultVoUtils.success(hi); } catch (DemoException demoException) { return ResultVoUtils.error(demoException); } } @GetMapping(value = "/request-get") public ResultVo requestGet() { String url = "http://localhost:8888/employee/query/2"; ResultVo resultVo = restTemplateUtils.get(url, new EmployeeVoParameterizedTypeReference()); LOGGER.info("code: {}", resultVo.getCode()); EmployeeVo employeeVo = resultVo.getResult().getData().get(0); return ResultVoUtils.success(null); } @GetMapping(value = "/request-post") public ResultVo requestPost() { Book book = new Book(); book.setAuthor("吴军"); book.setPublisher("人民邮电出版社"); book.setName("数学之美"); String url = "http://localhost:8888/v1/book/one-book"; ResultVo resultVo = restTemplateUtils.post(url, book, new BookParameterizedTypeReference()); LOGGER.info("code: {}", resultVo.getCode()); Book responseBook = resultVo.getResult().getData().get(0); return ResultVoUtils.success(null); } private static class EmployeeVoParameterizedTypeReference extends ParameterizedTypeReference> { } ; private static class BookParameterizedTypeReference extends ParameterizedTypeReference> { } ; } ``` ## 源代码地址 - [github](https://github.com/YoungBear/SpringBootDemo) - [gitee](https://gitee.com/YoungBear2023/spring-boot-demo)