赞
踩
我们使用SpringBoot的脚手架Spring Initializr创建,如图所示:
最开始做项目时候,组长说创建一个 springboot 2.5.4 的项目,mysql使用 5.6.X ,maven使用是3.6.X。其实最开始我也没有多想,直接照做了,但是后面回想自己平时看到的SpringBoot开源代码,有的是使用的是2.5.X,有的是使用2.6.X,还有的是使用2.7.X版本的,除了3以上版本在实际开发中没有见过,目前2版本的见到的太多版本号不一样的了。难道只要是2版本,都可以随意使用?当然我们知道不同的版本肯定是有差异的,每个版本都存在一些bug,后面的版本会对前一个版本进行修护和升级,也有一些方法,规则的调整。
所以说,如果要是一个人开发,只要你不用到每个框架版本的新特性,使用一些常规的操作,其实也不用太关注版本,但是实际情况是,往往后端不是你一个人在开发,要是每个人版本都不一样,万一出现了什么bug,排查起来也会比统一版本的情况下排查减少很多不必要的麻烦。所以开发中项目指定版本这里存在两个目的,一个是:统一版本,方便管理(跟每家公司有自己的代码规约一样,遵守就行了),第二个目的,降低风险,不使用版本太高的框架,且往往使用常用的框架版本进行开发,开发环境也比较熟悉。当然最后还有一个,多看看官网,多了解一些框架的不同版本特性,也有助于自己开发。
spring2.X版本在2023年11月24日停止维护了,因此创建spring项目时不再有2.X版本的选项,只能从3.1.X版本开始选择而Spring3.X版本不支持JDK8,JDK11,最低支持JDK17,因此JDK8也无法选择了,如图所示:
当然,停止维护只代表我们无法用idea主动创建spring2.X版本的项目了,不代表我们无法使用。目前阿里云还是支持创建Spring2.X版本的项目的,修改Server URL为https://start.aliyun.com,如图所示:
现在可以创建项目了,如图所示:
点击Next,建议选择2.7.x版本,并且根据项目需求添加依赖如图所示:
常用的依赖说明一下:
至此,简单的SpringBoot项目算创建完成了。
1、创建配置文件
项目刚创建完成时,默认的配置文件是application.properties文件,当然我们也可以创建application.yml文件。如果在yml文件中没有输入提示,需要到设置File Types中检查是否设置了ymal文件,如图所示:
2、创建项目结构
3、配置maven
在这里配置本地Maven本地路径、Maven仓库。在本地Maven的settings.xml中会配置maven的镜像资源等信息。
4、 下载相关依赖
在这里我们下载之前配置好的依赖,一般项目创建后会默认下载
5、 配置基础内容
在配置文件中配置一些基本的内容:
server: port: 8080 # 端口号 servlet: context-path: /myspringboot001 #项目根路径(前面必须加/) spring: # 项目名称 application: name: my-spring-boot001 # Mysql配置 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3307/my-springboot-001?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 username: root password: root1998 # Mybatis配置 mybatis: mapper-locations: classpath:mappers/*.xml #指定Mybatis的Mapper文件 type-aliases-package: com.example.myspringboot001.*.entity #指定Mybatis的实体目录
6、 配置Mybatis包扫描路径
我们在启动类上配置Mybatis的包扫描路径,用注解@MapperScan:
@SpringBootApplication
@MapperScan(value = {"com.example.myspringboot001.**.mapper"})
public class MySpringboot001Application {
public static void main(String[] args) {
SpringApplication.run(MySpringboot001Application.class, args);
}
}
以上配置好之后,我们就可以启动springboot项目。浏览器输入:http://localhost:8080/myspringboot001/ 后出现如下内容,说明项目启动成功,如图所示:
在实际开发中,我们一般都会有好几套运行环境。比如开发环境、测试环境、生产环境等等
我们不可能每次都去修改一个配置文件,这就显得很麻烦。下面我们主要说一说怎么配置多环境。
1、 修改application.yml配置文件
spring:
# 项目名称
application:
name: my-spring-boot001
# 当前配置文件
profiles:
active: dev
2、创建多环境配置文件
上面的配置,项目在启动的时候就会加载application.yml(主)和application-dev.yml(副)配置文件。
注意:如果主配置文件和副配置文件的配置项冲突的时候,会优先使用副配置文件的配置项。
DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键id', `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名', `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户昵称', `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户密码', `sex` enum('1','2') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户性别', `birthday` date NULL DEFAULT NULL COMMENT '用户生日', `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户邮箱', `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户电话', `addr` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户地址', `stop_flag` enum('1','0') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户启用标志', `create_time` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '用户创建时间', `update_time` datetime(0) NULL DEFAULT NULL COMMENT '用户更新时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; INSERT INTO `sys_user` VALUES (1, 'xiezhr', '程序员小凡', '12345678', '1', '1999-09-19', 'xiezhr@qq.com', '13288888888', '云南省昆明市', '0', '2023-09-04 21:08:32', NULL); INSERT INTO `sys_user` VALUES (2, 'xiaoqi', '程序员晓柒', '123456', '1', '2020-10-04', 'xiaoqi@163.com', '13288888888', '云南文山', '0', '2023-09-04 21:09:42', NULL); INSERT INTO `sys_user` VALUES (3, 'xiaodeng', '财务小邓', '123456', '2', '2019-09-04', 'xiaodeng@qq.com', '13588888888', '云南文山', '0', '2023-09-04 21:10:43', NULL);
执行结果如图所示:
@Data public class SysUser implements Serializable { private static final long serialVersionUID = 123456789L; /** * 主键id */ private Integer id; /** * 用户名 */ private String username; /** * 用户昵称 */ private String nickname; /** * 用户密码 */ private String password; /** * 用户性别 */ private String sex; /** * 用户生日 */ private Date birthday; /** * 用户邮箱 */ private String email; /** * 用户电话 */ private String phone; /** * 用户地址 */ private String addr; /** * 用户启用标志 */ private String stopFlag; /** * 用户创建时间 */ private Date createTime; /** * 用户更新时间 */ private Date updateTime; }
数据访问对象,是MVC架构中负责与数据库进行交互的组件。它封装了数据库的访问操作,提供给Service层调用。Dao层通常包含一系列方法,用于对数据库进行增删改查操作,以及与数据库的连接、事务管理等。@Mapper表示这个接口是一个MyBatis的Mapper接口,用于定义数据库操作的方法。
@Mapper
public interface SysUserMapper {
/**
* 查询所有用户信息
* @return 所有用户信息
*/
List<SysUser> querySysUserList();
}
MyBatis的映射文件(mapper),用于操作数据库中的sys_user表。其中定义了一个resultMap用于映射查询结果到SysUser对象,还定义了一个select语句用于查询sys_user表中的所有用户信息。 id=“querySyserList” 必须与mapper接口中方法名一致。
<?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.example.myspringboot001.system.mapper.SysUserMapper"> <resultMap type="com.example.myspringboot001.system.entity.SysUser" id="SysUserMap"> <result property="id" column="id" jdbcType="INTEGER"/> <result property="username" column="username" jdbcType="VARCHAR"/> <result property="nickname" column="nickname" jdbcType="VARCHAR"/> <result property="password" column="password" jdbcType="VARCHAR"/> <result property="sex" column="sex" jdbcType="VARCHAR"/> <result property="birthday" column="birthday" jdbcType="TIMESTAMP"/> <result property="email" column="email" jdbcType="VARCHAR"/> <result property="phone" column="phone" jdbcType="VARCHAR"/> <result property="addr" column="addr" jdbcType="VARCHAR"/> <result property="stopFlag" column="stop_flag" jdbcType="VARCHAR"/> <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/> <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/> </resultMap> <!--查询所有用户信息--> <select id="querySysUserList" resultMap="SysUserMap"> select * from sys_user </select> </mapper>
这里需要注意的是,IDEA在创建Mybatis的Mapper XML文件时,是没有头部信息,往往我们需要去复制过来,这就会很麻烦,我们可以自定义Mybatis Mapper XML文件模板,这样我们创建Mapper XML时就会有头部信息了如图所示:
然后我们在新建文件时选择Mybatis Mapper XML就可以了,如图:
Service是MVC架构中负责处理业务逻辑的组件。它封装了业务逻辑的实现细节,提供给Controller调用。Service层通常包含一系列方法,用于处理各种业务需求,如数据处理、事务管理、业务规则校验等。
1、创建SysUserService接口
public interface SysUserService {
/**
* 查询所有用户信息
* @return 所有用户信息
*/
List<SysUser> querySysUserList();
}
2、创建SysUserServiceImpl实现类
@Service
public class SysUserServiceImpl implements SysUserService {
@Resource
private SysUserMapper userMapper;
@Override
public List<SysUser> querySysUserList() {
return userMapper.querySysUserList();
}
}
Controller是MVC架构中负责接收用户请求并处理的组件。它接收来自用户的请求,并根据请求的内容调用相应的Service方法进行业务处理,然后返回结果给用户。Controller通常负责路由请求、参数验证、调用Service等操作。
1、创建SysUserController
@RestController @RequestMapping("/sysUser") public class SysUserController { @Autowired private SysUserService sysUserService; /** * 查询所有用户信息 * @return */ @RequestMapping(value = "/querySysUser",method = RequestMethod.GET) public List<SysUser> querySysUser(){ return sysUserService.querySysUserList(); } }
到此我们三大组件的代码都写完了,接下来我们来看看我们写好的接口,PostMan地址栏输入:http://localhost:8080/myspringboot001/sysUser/querySysUser,如图所示:
我们可以看到返回的时间格式是"2020-10-03T16:00:00.000+00:00"这样的,可读性很差。其实呢,日期格式化非常简单,我们只需要在之前定义好的实体类SysUser的日期属性上加上一个注解**@JsonFormat**即可:
import com.fasterxml.jackson.annotation.JsonFormat;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date birthday;
我们来测试一下,通过格式化的日期就是我们习惯的日期格式了,如图所示:
为了保证所有接口返回的数据格式一致,减少重复代码编写。我们将对返回结果进行统一处理。
具体返回结果格式如下:
{
"code": 200, // 状态码,表示请求的处理结果
"message": "请求成功", // 状态消息,对请求结果的简要描述
"data": { // 数据对象,用于存储具体的返回数据
"key1": "value1",
"key2": "value2"
}
}
它位于com.example.myspringboot001.common包中,可以由不同的类来实现,实现一致且统一的结果码和消息的处理和返回:
public interface IResultCode {
/**
* 获取状态码
* @return 状态码
*/
String getCode();
/**
* 获取状态信息
* @return 状态信息
*/
String getMsg();
}
定义了一个枚举类 ResultCode ,它实现了 IResultCode 接口,并包含了一些常见的响应码和对应的消息:
public enum ResultCode implements IResultCode, Serializable { SUCCESS("200","成功"), NOT_FOUND("404","未找到"), INTERNAL_SERVER_ERROR("500","服务器内部错误"); private String code; private String msg; ResultCode(String code, String msg){ this.code = code; this.msg = msg; } @Override public String getCode() { return code; } @Override public String getMsg() { return msg; } }
定义系统中常见的响应码和对应的消息,用于表示不同的业务场景或操作的执行结果每个枚举常量都包含一个 code 和一个 msg ,分别表示响应码和消息内容枚举常量包括了一些常见的响应码,如 SUCCESS 表示成功, INTERNAL_SERVER_ERROR 服务器内部错误, NOT_FOUND 表示未找到。
定义了一个名为 Result 的类,用于表示统一的响应结构体:
@Data public class Result<T> implements Serializable { private static final long serialVersionUID = 1L; private String code; private String msg; private T data; public static<T> Result<T> success() { return success(null); } public static<T> Result<T> success(T data) { Result result = new Result<>(); result.setCode(ResultCode.SUCCESS.getCode()); result.setMsg(ResultCode.SUCCESS.getMsg()); result.setData(data); return result; } public static <T> Result<T> error(String msg) { Result<T> result = new Result<>(); result.setCode(ResultCode.ERROR.getCode()); result.setMsg(ResultCode.ERROR.getMsg()); return result; } }
到此,统一响应返回我们已经封装好了,我们来改造一下Controller中的代码看看效果。
1、SysUserController未改之前:
@RequestMapping(value = "/querySysUser",method = RequestMethod.GET)
public List<SysUser> querySysUser(){
return sysUserService.querySysUserList();
}
2、SysUserController未改之后:
@RequestMapping(value = "/querySysUser",method = RequestMethod.GET)
public Result querySysUser(){
return Result.success(sysUserService.querySysUserList());
}
再次测试返回的数据:
从上面的返回结果,我们会发现将密码等敏感信息返回到了前端,这是非常不可取的这时,我们就需要根据前端的需求,灵活地选择需要展示的数据字段。
定义一个需要返回前端的VO
@Data public class SysUserVo { /** * 用户名 */ private String username; /** * 用户昵称 */ private String nickname; /** * 用户性别 */ private String sex; /** * 用户生日 */ @JsonFormat(pattern = "yyyy-MM-dd") private Date birthday; /** * 用户邮箱 */ private String email; /** * 用户电话 */ private String phone; /** * 用户地址 */ private String addr; }
SysUserService改造前
/**
* 查询所有用户信息
* @return 所有用户信息
*/
List<SysUser> querySysUserList();
SysUserServiceImpl改造前
@Override
public List<SysUser> querySysUserList() {
System.out.println(sysUserMapper);
return sysUserMapper.querySysUserList();
}
SysUserService改造后
/**
* 查询所有用户信息
* @return 所有用户信息
*/
List<SysUserVo> querySysUserList();
SysUserServiceImpl改造后
@Override
public List<SysUserVo> querySysUserList() {
List<SysUserVo> sysUserVos = new ArrayList<>();
List<SysUser> sysUsers = sysUserMapper.querySysUserList();
// 将po的值复制到vo中
sysUsers.forEach(sysUser -> {
SysUserVo vo = new SysUserVo();
BeanUtils.copyProperties(sysUser, vo);
sysUserVos.add(vo);
});
return sysUserVos;
}
我们再次用postman测试,输入http://localhost:8080/myspringboot001/sysUser/querySysUser,结果如图所示:
日常开发中,我们处理异常一般都会用到try-catch 、throw和throws 的方式抛出异常。这种方式不仅仅程序员处理麻烦,对用户来说也不太友好我们都希望不用写过多的重复代码处理异常,又能提升用户体验。这时候全局异常处理就显得很便捷很重要了。
Springboot对于异常的处理也做了不错的支持,它提供两个注解供我们使用。
我们在Result 类中添加如下两个方法来处理自定义异常和其他异常返回结果:
//自定义异常返回的结果 public static <T> Result<T> bussinessErr(BusinessException e) { Result<T> result = new Result<>(); result.setCode(e.getErrorCode()); result.setMsg(e.getErrorMsg()); result.setData(null); return result; } //其他异常处理方法返回的结果 public static <T> Result<T> otherErr(ResultCode resultCode) { Result<T> result = new Result<>(); result.setCode(resultCode.getCode()); result.setMsg(resultCode.getMsg()); result.setData(null); return result; }
在com.example.myspringboot001.common.exception包中新建BusinessException异常类:
public class BusinessException extends RuntimeException{ private String errorCode; private String errorMsg; public BusinessException() { } public BusinessException(String errorCode, String errorMsg) { this.errorCode = errorCode; this.errorMsg = errorMsg; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } }
我们自定义一个全局异常处理类,来处理各种异常,包括自己定义的异常和内部异常 。这样可以简化不少代码,不用自己对每个异常都使用try,catch的方式来实现。
在com.example.myspringboot001.common.handler包中新建GlobalExceptionHandler全局异常处理类:
@RestControllerAdvice public class GlobalExceptionHandler { /** * 处理自定义异常 * */ @ExceptionHandler(value = BusinessException.class) @ResponseBody public<T> Result<T> bizExceptionHandler(BusinessException e) { return Result.bussinessErr(e); } /** * 处理其他异常 * */ @ExceptionHandler(value = Exception.class) @ResponseBody public Result exceptionHandler(Exception e) { return Result.otherErr(ResultCode.ERROR); } }
我们在SysUserController 中添加如下代码来测试下异常,看看能不能捕获到:
@RequestMapping("/getBusinessException")
public Result DeException(){
throw new BusinessException("400","我出错了");
}
@RequestMapping("/getException")
public Result Exception(){
Result result = new Result();
int a = 1 / 0;
return result;
}
日志记录应用程序的运行状态,通过日志开发者可以更好的了解应用程序的运行情况当系统出现bug时,也能通过日志快速定位问题和解决问题。
我们需要需要选择一个日志门面 和日志实现,Spring Boot默认集成了SLF4j 和Logback作为日志实现框架。如果您使用Maven构建项目,通常无需手动添加Logback依赖,因为Spring Boot的起步依赖(starter dependencies)中已经包含了它。
1、日志输出分析,如图所示:
2、日志级别
日志级别由低到高如下
TRACE < DEBUG< INFO< WARN < ERROR
如果设置为 WARN ,则低于 WARN 的信息都不会输出 Spring Boot中默认配置是INFO级别。
3、调整日志级别
可以在配置文件application.yml中设置:
logging.level.root=DEBUG
或者在运行Spring Boot应用程序时,通过命令行参数来设置日志级别
java -jar your-application.jar --logging.level.root=DEBUG
4、日志写到文件中
需在application.properties或application.yml配置文件中设置logging.file.path或logging.file.name属性。
logging:
file:
path: /myspringboot/log # 只能指定路径,文件名默认为 spring.log,这里相当于window的 E:\myspringboot\log\spring.log
#name: /myspringboot/log/my.log # 可以指定文件路径和文件名,这里相当于window的 E:\myspringboot\log\my.log
#name: my.log 使用相对路径,这里相当于window的 E:\WorkPlace\IDEA\my-springboot-001\my.log
注意:logging.file.path和logging.file.name只能生效一个,在配置了两者的情况下,以logging.file.name的配置为准。
1、使用官方例子
Logger logger = LoggerFactory.getLogger(SysUserController.class);
@Autowired
private SysUserService sysUserService;
/**
* 查询所有用户信息
* @return
*/
@RequestMapping(value = "/querySysUser",method = RequestMethod.GET)
public Result querySysUser(){
String name = "tanya";
logger.info("this name is {}", name);
return Result.success(sysUserService.querySysUserList());
}
2、使用lombok插件
第一种方法中,每次使用都要创建了一个名为 logger 的Logger对象,使用起来有点繁琐。这里我们引入注解方式实现。使用注解**@Slf4j** 需要安装lombok插件。
@Slf4j public class SysUserController { @Autowired private SysUserService sysUserService; /** * 查询所有用户信息 * @return */ @RequestMapping(value = "/querySysUser",method = RequestMethod.GET) public Result querySysUser(){ log.info("this name is {}", name); return Result.success(sysUserService.querySysUserList()); } }
可以用{} 占位符来拼接字符串,而不需要使用+来连接字符串。
前面几节说的都是springboot基本日志配置,如果这些都不能满足我们的需求,我们就需要添加logback-spring.xml 官方推荐的配置文件进行配置。
注意:如果同时存在logback.xml和logback-spring.xml,Spring Boot 将会优先选择 logback-spring.xml 作为日志配置。logback.xml多用于非springboot项目;logback-spring.xml只能用于springboot项目,即带有@SpringBootApplication启动程序中才生效,在main或者Junit中依然不生效。并且这两个文件的配置项优先于application.yml的日志配置。
logback-spring.xml 中 配置了两个 分别是
<?xml version="1.0" encoding="UTF-8"?> <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 --> <configuration> <!-- SpringBoot默认logback的配置 --> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <springProperty scope="context" name="APP_NAME" source="spring.application.name"/> <property name="LOG_HOME" value="/logs/${APP_NAME}"/> <!--1. 输出到控制台--> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <!-- <withJansi>true</withJansi>--> <!--此日志appender是为开发使用,只配置最低级别,控制台输出的日志级别是大于或等于此级别的日志信息--> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <encoder> <Pattern>${CONSOLE_LOG_PATTERN}</Pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- 2. 输出到文件 --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 当前记录的日志文档完整路径 --> <file>${LOG_HOME}/log.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} -%5level ---[%15.15thread] %-40.40logger{39} : %msg%n%n</pattern> <charset>UTF-8</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!--这里是超出大小后新建的文件名,并且保存的是分割前面的旧日志,新日志还是在log.log中--> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>5KB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 临界值过滤器,输出大于INFO级别日志 --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> </appender> <!-- 开发环境输出至控制台和文件 --> <springProfile name="dev"> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> </springProfile> <!-- 生产环境输出至控制台和文件 --> <springProfile name="prod"> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> </springProfile> </configuration>
最终完整的项目结构如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。