Tlias系统(部门管理)
Tlias系统(部门管理)
1.前言
1.1Restful风格
- REST(Representational State Transfer),表述性状态转换,它是一种软件架构风格。
- 传统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的用户
1.2工程搭建
-
创建SpringBoot工程, 并引入web开发起步依赖/mybatis,MySQL驱动.lombok
-
创建项目
![image-20251205100101414]()
-
-
床见数据库及其对应的表结构, 并在application.yml中配置数据库的基本信息
-
创建tlias数据库, 并准备dept部门表
CREATE TABLE dept ( id int unsigned PRIMARY KEY AUTO_INCREMENT COMMENT 'ID, 主键', name varchar(10) NOT NULL UNIQUE COMMENT '部门名称', create_time datetime DEFAULT NULL COMMENT '创建时间', update_time datetime DEFAULT NULL COMMENT '修改时间' ) COMMENT '部门表'; INSERT INTO dept VALUES (1,'学工部','2023-09-25 09:47:40','2024-07-25 09:47:40'), (2,'教研部','2023-09-25 09:47:40','2024-08-09 15:17:04'), (3,'咨询部','2023-09-25 09:47:40','2024-07-30 21:26:24'), (4,'就业部','2023-09-25 09:47:40','2024-07-25 09:47:40'), (5,'人事部','2023-09-25 09:47:40','2024-07-25 09:4`` ``:40'), (6,'行政部','2023-11-30 20:56:37','2024-07-30 20:56:37'); -
在application.yml配置文件中配置数据库的连接信息
spring: application: name: tlias-web-management #mysql连接配置 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
-
-
准备基础包结构, 并引入实体类Dept及统一的响应结果封装类Result
-
准备基础包结构
![image-20251205100519425]()
-
实体类Dept
package com.itheima.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDateTime; @Data @NoArgsConstructor @AllArgsConstructor public class Dept { private Integer id; private String name; private LocalDateTime createTime; private LocalDateTime updateTime; } -
统一响应结构Result
package com.itheima.pojo; import lombok.Data; import java.io.Serializable; /** * 后端统一返回结果 */ @Data public class Result { private Integer code; //编码:1成功,0为失败 private String msg; //错误信息 private Object data; //数据 public static Result success() { Result result = new Result(); result.code = 1; result.msg = "success"; return result; } public static Result success(Object object) { Result result = new Result(); result.data = object; result.code = 1; result.msg = "success"; return result; } public static Result error(String msg) { Result result = new Result(); result.msg = msg; result.code = 0; return result; } } -
基础代码结构
![image-20251205101006452]()
-
DeptMapper
package com.itheima.mapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface DeptMapper { } -
DeptService
package com.itheima.service; public interface DeptService { } -
DeptServiceImpl
package com.itheima.service.impl; import com.itheima.service.DeptService; import org.springframework.stereotype.Service; @Service public class DeptServiceImpl implements DeptService { } -
DeptController
package com.itheima.controller; import org.springframework.web.bind.annotation.RestController; /** * 部门管理控制器 */ @RestController public class DeptController { }
-
2. 查询部门
2.1 基本实现

- Controller层,负责接收前端发起的请求,并调用service查询部门数据,然后响应结果。
- Service层,负责调用Mapper接口方法,查询所有部门数据。
- Mapper层,执行查询所有部门数据的操作。
代码实现
-
Conntroller层
在
DeptController中,增加list方法,代码如下:/** * 部门管理控制器 */ @RestController public class DeptController { @Autowired private DeptService deptService; /** * 查询部门列表 */ @RequestMapping("/depts") public Result list(){ List<Dept> deptList = deptService.findAll(); return Result.success(deptList); } } -
Service层
在
DeptService中,增加findAll方法,代码如下:public interface DeptService { /** * 查询所有部门 */ public List<Dept> findAll(); }在
DeptServiceImpl中,增加findAll方法,代码如下:@Service public class DeptServiceImpl implements DeptService { @Autowired private DeptMapper deptMapper; public List<Dept> findAll() { return deptMapper.findAll(); } } -
Mapper层
在
DeptMapper中,增加findAll方法,代码如下:@Mapper public interface DeptMapper { /** * 查询所有部门 */ @Select("select * from dept") public List<Dept> findAll(); }
接口测试
如何限制请求方式:
方法一:
- 在controller方法的@RequestMapping注解中通过method属性来限定。
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
/**
* 查询部门列表
*/
@RequestMapping(value = "/depts", method = RequestMethod.GET)
public Result list(){
List<Dept> deptList = deptService.findAll();
return Result.success(deptList);
}
}
方式二:
- 在controller方法上使用,@RequestMapping的衍生注解 @GetMapping。 该注解就是标识当前方法,必须以GET方式请求。
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
/**
* 查询部门列表
*/
@GetMapping("/depts")
public Result list(){
List<Dept> deptList = deptService.findAll();
return Result.success(deptList);
}
}
上述两种方式,在项目开发中,推荐使用第二种方式,简洁、优雅。
- GET方式:@GetMapping
- POST方式:@PostMapping
- PUT方式:@PutMapping
- DELETE方式:@DeleteMapping
数据封装
-
实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。
-
如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装。
解决方案:
- 手动结果映射
在DeptMapper接口方法上,通过 @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.2前后端联调
- 运行nginx
- 访问http://localhost:90
- location:用于定义匹配特定uri请求的规则。
- ^~ /api/:表示精确匹配,即只匹配以/api/开头的路径。
- rewrite:该指令用于重写匹配到的uri路径。
- proxy_pass:该指令用于代理转发,它将匹配到的请求转发给位于后端的指令服务器。
3.删除部门
3.1 需求
删除部门数据。在点击 "删除" 按钮,会根据ID删除部门数据。
3.2 思路分析

3.3 简单参数接收
-
方法一:通过原始的HttpServletRequest对象获取请求参数
/** * 根据ID删除部门 - 简单参数接收: 方式一 (HttpServletRequest) */ @DeleteMapping("/depts") public Result delete(HttpServletRequest request){ String idStr = request.getParameter("id"); int id = Integer.parseInt(idStr); System.out.println("根据ID删除部门: " + id); return Result.success(); } -
方法二: 通过Spring提供的@RequestParam注解,将请求的参数绑定给方法形参
@DeleteMapping("/depts") public Result delete(@RequestParam("id") Integer deptId){ System.out.println("根据ID删除部门: " + deptId); return Result.success(); }@RequestParam注解的value属性,需要与前端传递的参数名保持一致 。[!NOTE]
@RequestParam注解required属性默认为true,代表该参数必须传递,如果不传递将报错。 如果参数可选,可以将属性设置为false。
-
方法三: 如果请求参数参数名与形参变量名相同,直接定义方法形参即可接受.(省略@RequestParam)
@DeleteMapping("/depts") public Result delete(Integer id){ System.out.println("根据ID删除部门: " + deptId); return Result.success(); }
3.4 代码实现
1). Conteoller层
在DeptMapper中, 增加delete方法:
/**
* 根据id删除部门 - delete http://localhost:8080/depts?id=1
*/
@DeleteMapping("/depts")
public Result delete(Integer id){
System.out.println("根据id删除部门, id=" + id);
deptService.deleteById(id);
return Result.success();
}
2). Service层
在DeptSevice中,增加deleteById方法:
/**
* 根据id删除部门
*/
void deleteById(Integer id);
在DeptServiceImpl中,增加deleteById方法:
public void deleteById(Integer id) {
deptMapper.deleteById(id);
}
3). Mapper层
在DeptMapper中, 增加deleteById方法:
/**
* 根据id删除部门
*/
@Delete("delete from dept where id = #{id}")
void deleteById(Integer id);
如果Mapper接口方法形参只有一个普通类型的参数, #{…}里面的属性名可以随便写, 如: #{id}
对于DML语句来说,执行完毕,也是有返回值的, 返回值代表的是增删改操作,影响的记录数, 所有可以将执行DML语句的方法返回值设置为Integer. 但是一般开发时,是不需要这个返回值的, 所有也可以设置为void
4. 新增部门
4.1 思路分析

4.2 json参数接收
在Controller中, 需要接收前端传递的请求参数..
- JSON格式的参数,通常会使用一个实体对象进行接收
- 规则: JSON数据的键名与方法形参对象的属性名相同, 并需要使用@RequesBody注解标识
前端传递的请求参数格式为json,内容如下:{"name": "研发部"}
这里, 我们可以通过一个对象来接收, 只需要保证对象中有name属性

4.3 代码实现
1). Conntroller层
在DeptController中增加方法save:
/**
* 新增部门 - POST http://localhost:8080/depts 请求参数:{"name":"研发部"}
*/
@PostMapping("/depts")
public Result save(@RequestBody Dept dept){
System.out.println("新增部门, dept=" + dept);
deptService.save(dept);
return Result.success();
}
2). Service层
在DeptService中增加方法save:
/**
* 新增部门
*/
void save(Dept dept);
在DeptServiceImpl中增加save方法, 完成部门的操作:
public void save(Dept dept) {
//补全基础属性
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
//保存部门
deptMapper.insert(dept);
}
3). Mapper层
/**
* 保存部门
*/
@Insert("insert into dept(name,create_time,update_time) values(#{name},#{createTime},#{updateTime})")
void insert(Dept dept);
如果在Mapper接口中,需要传递多个参数,可以把多个参数封装到一个对象中. 在SQL语句中获取参数的时候, #{…}里面写的是对象的属性名(注意是属性名,不是表的字段名)
5.修改部门
对于任何业务的修改功能来说, 一般都会分为两部进行: 查询回显/修改数据
5.1查询回显
5.1.1 思考

5.1.2 路径参数接收
/depts/1这种在url中传递的参数, 我们称之为路径参数
路径参数: 通过请求URL直接传递参数, 使用{…}来标识该路径参数,需要使用@PathVariable获取路径参数

5.1.3 代码实现
1). Conntroller层
在DeptController中增加deptById方法
/**
* 根据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);
}
2). Service层
在DeptService中增加个tById方法
/**
* 根据id查询部门
*/
Dept getById(Integer id);
在DeptServiceImpl中增加deptbyId方法
public Dept getById(Integer id) {
return deptMapper.getById(id);
}
3). Mapper层
在DeptMapper中增加getById方法
/**
* 根据ID查询部门数据
*/
@Select("select id, name, create_time, update_time from dept where id = #{id}")
Dept getById(Integer id);
5.2 修改数据
5.2.1 思路分析

通过接口文档,我们可以看到前端传递的请求参数是json格式的请求参数, 在Controller的方法中,我们可以通过RequestBody注解来接收, 并将其封装到一个对象中
5.2.2 代码实现
1). Controller层
在DeptController中增加update方法:
/**
* 修改部门 - PUT http://localhost:8080/depts 请求参数:{"id":1,"name":"研发部"}
*/
@PutMapping("/depts")
public Result update(@RequestBody Dept dept){
System.out.println("修改部门, dept=" + dept);
deptService.update(dept);
return Result.success();
}
/**
* 修改部门 - PUT http://localhost:8080/depts 请求参数:{"id":1,"name":"研发部"}
*/
@PutMapping("/depts")
public Result update(@RequestBody Dept dept){
System.out.println("修改部门, dept=" + dept);
deptService.update(dept);
return Result.success();
}
2). Service层
在DeptService中增加update方法
/**
* 修改部门
*/
void update(Dept dept);
在DeptServiceImpl中增加update方法,由于是修改操作,每一次修改数据,都需要更新updateTime
public void update(Dept dept) {
//补全基础属性
dept.setUpdateTime(LocalDateTime.now());
//保存部门
deptMapper.update(dept);
}
3). Mapper层
在DeptMapper中增加update方法
/**
* 更新部门
*/
@Update("update dept set name = #{name},update_time = #{updateTime} where id = #{id}")
void update(Dept dept);
5.2.3 @RequestMapping
发现在Dept controller 中定义的方法,所有的请求路径, 都是/Depts开头的,我们可以将这个公共的路径/depts抽取到类上,那在各个方法上, 就可以省略这个/depts路径
@RequestMapping(“/depts”)

一个完整的请求路径,应该是类上的@RequestMapping的value属性 + 方法上的@RequestMapping的value属性
6. 日志技术
6.1 概述
-
为什么要记录日志
- 便于追踪应用程序中的数据信息、程序的执行过程。
- 便于对应用程序的性能进行优化。
- 便于应用程序出现问题之后,排查问题,解决问题。
- 便于监控系统的运行状态。
- ... ...
-
之前我们编写程序的时候, 也可以通过System.out.println(…)来输入日志, 为什么我们还要学习单独的日志技术呢
这是因为, 如果通过System.out.println(...)来记录日志, 会存在一下几点问题
- 硬编码.所有记录日志的代码, 都是硬编码, 没有办法做到灵活控制. 要想不输出这个日志了. 之恩个删掉记录日志的代码
- 只能输入日志到控制台
- 不便于程序的扩展.维护
6.2 日志入门

- JUL: 这是JavaSE平台提供的官方日志框架, 也被称为JUL. 配置相对简单, 但不够灵活, 性能较差
- Log4j: 一个流行的日志框架, 提供了灵活的配置选项, 支持多种输出目标
- Logback: 基于Log4j升级而来, 提供了更多的功能和配置选项, 性能优于Log4j
- Slf4j: (Slimple Logging Facade for Java) 简单日志门面, 提供了一套日志操作的标准接口以及抽象类, 允许程序使用不同的底层日志框架
6.3 Logback入门
1). 准备工作: 引入Logback的依赖(springboot中无需引入, 在springboot中已经传递了此依赖)
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
2). 引入配置文件logback.xml
<?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>
3). 记录日志: 定义日志记录对象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("结束计算...");
}
}
6.4 Logback日志配置文件
Logback日志文件的框架的配置文件叫Logback.xml
该文件是对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>
6.5 Logback日志级别
日志级别是指日志信息的类型, 日志都会分级别, 常见的日志级别如下(优先级由低到高):
- trace 追踪,记录程序运行轨迹 【使用很少】
- debug 调试,记录程序调试过程中的信息,实际应用中一般将其视为最低级别 【使用较多】
- info 记录一般信息,描述程序运行的关键事件,如:网络连接、io操作 【使用较多】
- warn 警告信息,记录潜在有害的情况 【使用较多】
- error 错误信息 【使用较多】
可以在配置文件Logback.xml中灵活的 控制输出那个类型的日志
<!-- 日志输出级别 -->
<root level="info">
<!--输出到控制台-->
<appender-ref ref="STDOUT" />
<!--输出到文件-->
<appender-ref ref="FILE" />
</root>
6.6 案例日志记录
/**
* 部门管理控制器
*/
@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
/**
* 查询部门列表
*/
//@RequestMapping(value = "/depts", method = RequestMethod.GET)
@GetMapping
public Result list(){
//System.out.println("查询部门列表");
log.info("查询部门列表");
List<Dept> deptList = deptService.findAll();
return Result.success(deptList);
}
/**
* 根据id删除部门 - delete http://localhost:8080/depts?id=1
*/
@DeleteMapping
public Result delete(Integer id){
//System.out.println("根据id删除部门, id=" + id);
log.info("根据id删除部门, id: {}" , id);
deptService.deleteById(id);
return Result.success();
}
/**
* 新增部门 - POST http://localhost:8080/depts 请求参数:{"name":"研发部"}
*/
@PostMapping
public Result save(@RequestBody Dept dept){
//System.out.println("新增部门, dept=" + dept);
log.info("新增部门, dept: {}" , dept);
deptService.save(dept);
return Result.success();
}
/**
* 根据ID查询 - GET http://localhost:8080/depts/1
*/
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id){
//System.out.println("根据ID查询, id=" + id);
log.info("根据ID查询, id: {}" , id);
Dept dept = deptService.getById(id);
return Result.success(dept);
}
/**
* 修改部门 - PUT http://localhost:8080/depts 请求参数:{"id":1,"name":"研发部"}
*/
@PutMapping
public Result update(@RequestBody Dept dept){
//System.out.println("修改部门, dept=" + dept);
log.info("修改部门, dept: {}" , dept);
deptService.update(dept);
return Result.success();
}
}
lombok中提供的@Slf4j注解,可以简化定义日志记录器这步操作。添加了该注解,就相当于在类中定义了日志记录器,就下面这句代码:
private static Logger log = LoggerFactory. getLogger(Xxx. class);




浙公网安备 33010602011771号