目录
3). 日志开关配置 (开启日志(ALL),取消日志(OFF))
Restful风格:
在前后端分离的开发模式中,前后端开发人员都需要根据提前定义好的接口文档,来进行前后端功能的开发。
传统URL风格如下:
http://localhost:8080/user/getById?id=1 GET:查询id为1的用户
-
http://localhost:8080/user/saveUser POST:新增用户
-
http://localhost:8080/user/updateUser POST:修改用户
-
http://localhost:8080/user/deleteUser?id=1 GET:删除id为1的用户
我们看到,原始的传统URL呢,定义比较复杂,而且将资源的访问行为对外暴露出来了。而且,对于开发人员来说,每一个开发人员都有自己的命名习惯,就拿根据id查询用户信息来说的,不同的开发人员定义的路径可能是这样的:getById
,selectById
,queryById
,loadById
... 。 每一个人都有自己的命名习惯,如果都按照各自的习惯来,一个项目组,几十号或上百号人,那最终开发出来的项目,将会变得难以维护,没有一个统一的标准。
基于REST风格URL如下:
-
http://localhost:8080/users/1 GET:查询id为1的用户
-
http://localhost:8080/users POST:新增用户
-
http://localhost:8080/users PUT:修改用户
-
http://localhost:8080/users/1 DELETE:删除id为1的用户
通过URL定位要操作的资源,通过HTTP动词(请求方式)来描述具体的操作。
-
GET : 查询
-
POST :新增
-
PUT : 修改
-
DELETE :删除
我们看到如果是基于REST风格,定义URL,URL将会更加简洁、更加规范、更加优雅。
代码结构:
1). Controller层
post添加 get查询 put修改 delete删除
get后无参数时 查询 全部 后有参数时用 @GetMapping("/{id}") 解析restful风格的参数
@RestController
@RequestMapping("/depts")
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping
public Result findAll(){
List<Dept> all = deptService.findAll();
return Result.Success(all);
}
/*@DeleteMapping
public Result delete(Integer id){
deptService.delete(id);
return Result.Success("删除成功");
}*/
@DeleteMapping
public Result delete(@RequestParam("id") Integer id){
deptService.delete(id);
return Result.Success("删除成功");
}
@PostMapping
public Result addDept(@RequestBody Dept dept){
deptService.addDept(dept);
return Result.Success("添加成功");
}
@GetMapping("/{id}")
public Result findById(@PathVariable Integer id){
Dept dept = deptService.findById(id);
return Result.Success(dept);
}
@PutMapping
public Result update(@RequestBody Dept dept){
deptService.updateDept(dept);
return Result.Success("修改成功");
}
}
2). Service层
接口:
public interface DeptService {
List<Dept> findAll();
Integer delete(Integer id);
void addDept(Dept dept);
Dept findById(Integer id);
void updateDept(Dept dept);
}
实现类:
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public List<Dept> findAll() {
return deptMapper.selectAll();
}
@Override
public Integer delete(Integer id) {
int i = deptMapper.deleteById(id);
return i;
}
@Override
public void addDept(Dept dept) {
dept.setCreate_time(LocalDateTime.now());
dept.setUpdate_time(LocalDateTime.now());
deptMapper.insert(dept);
}
@Override
public Dept findById(Integer id) {
Dept dept = deptMapper.selectById(id);
return dept;
}
@Override
public void updateDept(Dept dept) {
dept.setUpdate_time(LocalDateTime.now());
deptMapper.update(dept);
}
}
3). Mapper(dao)层
@Mapper
public interface DeptMapper {
@Select("select * from dept")
List<Dept> selectAll();
@Delete("delete from dept where id=#{id}")
int deleteById(Integer id);
@Insert("insert into dept values (null,#{name},#{create_time},#{update_time})")
void insert(Dept dept);
@Select("select * from dept where id=#{id}")
Dept selectById(Integer id);
@Update("update dept set name=#{name},update_time=#{update_time} where id=#{id}")
void update(Dept dept);
}
4).yml文件:
spring:
application:
name: tlias-manager-sys
datasource:
url: jdbc:mysql://127.0.0.1:3306/test
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
数据封装:
注意只有在查询时 数据库mybaits 框架自动返回对象时才会产生这个问题
当自定义实体类的 名字 和 数据库的字段名不完全一样时 在查询时:就会有不能自动封装的问题
解决方案:
-
手动结果映射
-
起别名
-
开启驼峰命名
1). 手动结果映射
在DaoMapper接口方法上,通过 @Results及@Result 进行手动结果映射。
@Results({@Result(column = "create_time", property = "createTime"),
@Result(column = "update_time", property = "updateTime")})
@Select("select id, name, create_time, update_time from dept")
public List<Dept> findAll();
2). 起别名
在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样。
@Select("select id, name, create_time createTime, update_time updateTime from dept")
public List<Dept> findAll();
3). 开启驼峰命名(推荐)
如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射。驼峰命名规则: abc_xyz => abcXyz
-
表中字段名:abc_xyz
-
类中属性名:abcXyz
在application.yml中做如下配置,开启开关。
mybatis:
configuration:
map-underscore-to-camel-case: true
删除部门:
-
方案一:通过原始的
HttpServletRequest
对象获取请求参数 -
-
方案二:通过Spring提供的
@RequestParam
注解,将请求参数绑定给方法形参
-
方案三:如果请求参数名与形参变量名相同,直接定义方法形参即可接收。(省略@RequestParam)
新增部门:
/**
* 根据ID查询 - GET http://localhost:8080/depts/1
*/
@GetMapping("/depts/{id}")
public Result getById(@PathVariable Integer id){
System.out.println("根据ID查询, id=" + id);
Dept dept = deptService.getById(id);
return Result.success(dept);
}
@RequestBody 注解 可以将post请求体中 传入的json 数据 自动封装为 Dept对象
@RequsetParam 可以自动获取 URL风格的传参 (localhost:8080/depts?id=3)例如
@DeleteMapping()
public Result delete(@RequestParam("id") Integer id){
deptService.delete(id);
return Result.Success("删除成功");
}
如果使用 restful 风格 传参 需要使用 @PathVariable 修饰参数
/**
* 根据ID查询 - GET http://localhost:8080/depts/1
*/
@GetMapping("/depts/{id}")
public Result getById(@PathVariable Integer id){
System.out.println("根据ID查询, id=" + id);
Dept dept = deptService.getById(id);
return Result.success(dept);
}
修改数据:
修改数据时用 PutMapping注解修饰方法 前端服务器 用put方法发送请求json数据 时 会根据键
配对 实体类中的 变量名 运用 @RequsetBody 注解自动封装到 实体类对象中
日志技术(重要):
日志框架:
准备工作:引入logback的依赖(springboot中无需引入,在springboot中已经传递了此依赖)
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
引入配置文件 logback.xml
(资料中已经提供,拷贝进来,放在 src/main/resources
目录下; 或者直接AI生成)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="ALL">
<appender-ref ref="STDOUT" />
</root>
</configuration>
记录日志:
使用@Slf4j 注解即可使用 会自动创建 Logger 对象
public class LogTest {
//定义日志记录对象
private static final Logger log = LoggerFactory.getLogger(LogTest.class);
@Test
public void testLog(){
log.debug("开始计算...");
int sum = 0;
int[] nums = {1, 5, 3, 2, 1, 4, 5, 4, 6, 7, 4, 34, 2, 23};
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
log.info("计算结果为: "+sum);
log.debug("结束计算...");
}
}
Logback配置文件:
1). 如果需要输出日志到控制台。添加如下配置:
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d 表示日期,%thread 表示线程名,%-5level表示级别从左显示5个字符宽度,%msg表示日志消息,%n表示换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
</encoder>
</appender>
2). 如果需要输出日志到文件。添加如下配置:
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件输出的文件名, %i表示序号 -->
<FileNamePattern>D:/tlias-%d{yyyy-MM-dd}-%i.log</FileNamePattern>
<!-- 最多保留的历史日志文件数量 -->
<MaxHistory>30</MaxHistory>
<!-- 最大文件大小,超过这个大小会触发滚动到新文件,默认为 10MB -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d 表示日期,%thread 表示线程名,%-5level表示级别从左显示5个字符宽度,%msg表示日志消息,%n表示换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
</encoder>
</appender>
3). 日志开关配置 (开启日志(ALL),取消日志(OFF))
<!-- 日志输出级别 -->
<root level="ALL">
<!--输出到控制台-->
<appender-ref ref="STDOUT" />
<!--输出到文件-->
<appender-ref ref="FILE" />
</root>
Logback日志级别:
trace 几乎不使用 会用 debug替代
lombok中提供的@Slf4j注解,可以简化定义日志记录器这步操作。添加了该注解,就相当于在类中定义了日志记录器,就下面这句代码:
private static Logger log = LoggerFactory. getLogger(Xxx. class);