当前位置: 首页 > news >正文

实战--Tlias教学管理系统(部门管理)

准备工作

开发规范--开发模式

1:查看接口文档:接口文档 - 飞书云文

2:了解开发流程

开发规范--Restful风格 

REST(Representational State Transfer),表述性状态转换,它是一种软件架构风格

注意:

1:REST 是风格,是约定方式,约定不是规定,可以打破。

2:描述功能模块通常使用复数形式(加s),表示此类资源,而非单个资源。如:users,books 

开发规范--Apifox

 

思考:

1:前后端都再并行开发,后端开发完对应的接口之后,如何对接口进行请求测试呢?

2: 前后端都在并行开发,前端开发过程中,如何获取到数据,测试页面的渲染展示呢?

这时我们需要用到 Apifox;

介绍:Apifox 是一款集成了 Api文档,Api调试,Api  Mock,Api测试的一体化协作平台

作用:接口文档管理,接口请求测试,Mock服务(就是 Apifox 为前端提供的模拟 URL 地址,访问这个模拟的 URL 地址,就返回对应的测试数据来供前端测试调试用的)

官网:https://apifox.com/

package com.itheima;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController // 当前类是一个请求处理类
public class HelloController {@RequestMapping("/hello") // 请求路径public String hello(String name){System.out.println("hello " + name);return "Hello " + name + " ~";}
}

小结:为什么要使用 Apifox?

由于浏览器地址栏发起的请求,都是 GET 方式的请求,如果我们需要发起 POST,PUT,DELETE,方式的请求,就需要借助于这类工具 

工程搭建

1:创建 SpringBoot 工程,并引入 web 开发起步依赖,mybatis,mysql驱动,lombok

2:创建数据库表dept,并在 application.yml 中配置数据库的基本信息

3:准备基础代码结构,并引入实体类 Dept 及统一的响应结果封装类 Result

spring:application:name: tlias-web-management#配置数据库的连接信息datasource:url: jdbc:mysql://localhost:3306/tliasdriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: bobo2005210#配置mybatismybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
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,'学工部','2024-09-25 09:47:40','2024-09-25 09:47:40'),(2,'教研部','2024-09-25 09:47:40','2024-09-09 15:17:04'),(3,'咨询部','2024-09-25 09:47:40','2024-09-30 21:26:24'),(4,'就业部','2024-09-25 09:47:40','2024-09-25 09:47:40'),(5,'人事部','2024-09-25 09:47:40','2024-09-25 09:47:40'),(6,'行政部','2024-11-30 20:56:37','2024-09-30 20:56:37');

查寻部门

接口开发

 

package com.itheima.controller;import com.itheima.pojo.Dept;
import com.itheima.pojo.Result;
import com.itheima.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
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.RestController;import java.util.List;@RestController // 保证返回的数据是 json 格式的数据
public class DeptController {@Autowiredprivate DeptService deptService;//@RequestMapping(value = "/depts", method = RequestMethod.GET)@GetMapping("/depts")public Result list(){System.out.println("查询全部部门的数据");List<Dept> dentist = deptService.findAll();return Result.success(dentist);}
}
package com.itheima.service.impl;import com.itheima.mapper.DeptMapper;
import com.itheima.pojo.Dept;
import com.itheima.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class DepeServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Overridepublic List<Dept> findAll() {return deptMapper.findAll();}
}
package com.itheima.mapper;import com.itheima.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface DeptMapper {@Select("select id, name, create_time, update_time from dept")List<Dept> findAll();
}

 但是这里还有一个bug,就是我们的 create_time 和 update_time 显示的是null

我们接下来要解决这个问题  

数据封装

实体类属性名 和 数据库表查询返回的字段名一致,mybatis 会自动封装

如果实体类属性名 和 数据库表查询返回的字段名不一致,不能自动封装

这里有三个解决方法

1:手动结果映射,通过 @Results 和 @Result 进行手动结果映射

package com.itheima.mapper;import com.itheima.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface DeptMapper {@Results({@Result(column = "update_time", property = "updateTime"),@Result(column = "create_time", property = "createTime")})@Select("select id, name, create_time, update_time from dept")List<Dept> findAll();
}

2: 起别名,在 SQL 语句中对不一样的列名起别名,让别名和实体类的属性名一样

package com.itheima.mapper;import com.itheima.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface DeptMapper {
//    方式一:   
//    @Results({
//            @Result(column = "update_time", property = "updateTime"),
//            @Result(column = "create_time", property = "createTime")
//    })
//    方式二:@Select("select id, name, create_time createTime, update_time updateTime from dept")List<Dept> findAll();
}

3: 开启驼峰命名,如果字段名与属性名符合驼峰命名规则,mybatis 会自动通过驼峰命名规则映射。

spring:application:name: tlias-web-management#配置数据库的连接信息datasource:url: jdbc:mysql://localhost:3306/tliasdriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: bobo2005210#配置mybatis
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true

前后端联调测试 

 1:将资料中提供的前端工程文件夹中的压缩包,拷贝到一个没有中文不带空格的目录下,解压。

2:启动 nginx.exe;

3:访问测试:http://localhost:90/index

 前端工程请求服务器的地址为:http://localhost:90/api/depts,是如何访问到后端的 tomcat 服务器的?

这里用到的技术是 nginx 的反向代理;

反向代理:一种网络架构,通过代理服务器为后端的服务器做代理,客户端的请求直接请求代理服务器,然后发给后端的服务器。(安全,灵活,负载均衡)

这个技术的代码写在 conf 文件夹里

1:location:用于定义匹配路径匹配的规则。

2:^~ /api/:表示精确匹配,即只匹配以 /api/ 开头的路径

3:rewrite:该指令用于重写匹配到的路径

4:proxy_pass:该指令用于代理转发,它将匹配到的请求转发给位于后端的指令服务器

删除部门

Controller层 接收参数

方式一:通过原始的 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 注解中的 required 属性默认为 true ,代表该参数必须传递,如果不传递将报错。如果参数可选,可以将属性设置为 false; 

方式三:如果请求参数名与形参变量名相同,直接定义方法形参即可接收。(省略@RequestParam )

    @DeleteMapping("/depts")public Result delete(Integer id){System.out.println("删除的id为" + id);return Result.success();}

 我们最推荐第三种方法

Service 层

    @Overridepublic void deleteById(Integer id) {deptMapper.delete(id);}

Dao 层 

    @Delete("delete from dept where id = #{id}")void delete(Integer id);

新增部门

Controller层 接收参数

查看接口文档,发现请求参数要求使用 json 格式,所以我们这里的操作和上面删除部门是不一样的。

JSON 格式的参数,通常由一个实体对象进行接收。

规则:JSON 数据的键名与方法形参对象的属性名相同,并需要使用 @RequestBody 注解标识

    @PostMapping("/depts")public Result add(@RequestBody Dept dept){System.out.println("新增了新的部门:" + dept);deptService.add(dept);return Result.success();}

Service 层 

这里别忘了要补全基础属性,因为前端没有传

    @Overridepublic void add(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.add(dept);}

Dao 层

    @Insert("insert into dept (name, create_time, update_time) values (#{name}, #{createTime}, #{updateTime})")void add(Dept dept);

根据 id 查询部门 -- 查询回显

Controller层 接收参数

查看接口文档,这里可以发现请求路径是 /depts/{id},和之前的请求路径又不一样,这里大括号里的 id 我们称为路径参数,即参数格式为路径参数

路径参数:通过请求 URL 直接传递参数,使用 {...} 来标识该路径参数,需使用 @PathVarialbe 获取。

    @GetMapping("/depts/{id}")public Result getInfo(@PathVariable("id") Integer id){System.out.println("查询了部门:" + id);return Result.success();}

当然,如果我这个方法的形参名和路径参数的参数名是一致的,Path 当中的 value 属性值就可以省略了

    @GetMapping("/depts/{id}")public Result getInfo(@PathVariable Integer id){System.out.println("查询了部门:" + id);return Result.success();}

最后根据接口文档,我们还要返回数据 data,所以完整版的是;

    @GetMapping("/depts/{id}")public Result getInfo(@PathVariable Integer id){System.out.println("查询了部门:" + id);Dept dept = deptService.getInfo(id);return Result.success(dept);}

Service 层 

    @Overridepublic Dept getInfo(Integer id) {return deptMapper.getInfo(id);}

Dao 层 

    @Select("select id, name, create_time, update_time from dept where id = #{id}")Dept getInfo(Integer id);

修改部门 -- 修改数据

 Controller层 接收参数

    @PutMapping("/depts")public Result update(@RequestBody Dept dept){System.out.println("修改了部门: " + dept);deptService.update(dept);return Result.success();}

Servie 层 

    @Overridepublic void update(Dept dept) {dept.setUpdateTime(LocalDateTime.now());deptMapper.update(dept);}

Dao 层 

    @Update("update dept set name = #{name}, update_time = #{updateTime} where id = #{id}")void update(Dept dept);

优化

我们可以发现,方法上的请求路径都是 /depts,所以我们可以把方法上的这个请求路经给给抽取到类上,注意路径参数要保留,完整的代码如下:
 

package com.itheima.controller;import com.itheima.pojo.Dept;
import com.itheima.pojo.Result;
import com.itheima.service.DeptService;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;@RequestMapping("/depts")
@RestController // 保证返回的数据是 json 格式的数据
public class DeptController {@Autowiredprivate DeptService deptService;//@RequestMapping(value = "/depts", method = RequestMethod.GET)@GetMappingpublic Result list(){System.out.println("查询全部部门的数据");List<Dept> dentist = deptService.findAll();return Result.success(dentist);}@DeleteMappingpublic Result delete(Integer id){System.out.println("删除的id为" + id);deptService.deleteById(id);return Result.success();}@PostMappingpublic Result add(@RequestBody Dept dept){System.out.println("新增了新的部门:" + dept);deptService.add(dept);return Result.success();}@GetMapping("/{id}")public Result getInfo(@PathVariable Integer id){System.out.println("查询了部门:" + id);Dept dept = deptService.getInfo(id);return Result.success(dept);}@PutMappingpublic Result update(@RequestBody Dept dept){System.out.println("修改了部门: " + dept);deptService.update(dept);return Result.success();}}

日志技术 

程序中的日志,是用来记录应用程序的运行信息,状态信息,错误信息等。

作用:数据追踪,性能优化,问题排查,系统监控等

JUL:这是 JavaSE 平台提供的官方日志框架,配置相对简单,但不够灵活,性能较差。

Log4j:一个流行的日志框架,提供了灵活的配置选项,支持多种输出目标。

Logback:基于 Log4j 升级而来,提供了更多的功能和配置选项,性能优于 Log4j。

Slf4j(Simple Logging Facade for Java):简单日志门面,提供了一套日志操作的标准接口及抽象类,允许应用程序使用不同的底层日志框架。

 Logback 快速入门

准备工作:引入 logback 的依赖 (springboot 项目中该依赖已传递),配置文件logback.xml.

记录日志:定义日志记录对象 Logger,调用方法(debuf / info / ...) 记录日志

我们可以直接使用  @Slf4j 来代替那一大串定义

package com.itheima;import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.time.LocalDateTime;public class LogTest {private  static final Logger log = LoggerFactory.getLogger(LogTest.class);@Testpublic void testLog(){
//        System.out.println(LocalDateTime.now() + " : 开始计算...");log.debug("开始计算。。。");int sum = 0;int[] nums = {1, 5, 3, 2, 1, 4, 5, 4, 6, 7, 4, 34, 2, 23};for (int num : nums) {sum += num;}log.info("计算结果为:" + sum);
//        System.out.println("计算结果为: "+sum);
//        System.out.println(LocalDateTime.now() + "结束计算...");log.debug("结束结算。。。");}}

<?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个字符宽度  %logger{50}: 最长50个字符(超出.切割)  %msg:日志消息,%n是换行符 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!-- 日志输出级别 --><root level="debug"><appender-ref ref="STDOUT" /></root>
</configuration>

我们还可以将上述 xml 文件中的 "debug" 改成 "off" 让其不再输出。 

Logback 配置文件详解

<?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个字符宽度,%logger显示日志记录器的名称, %msg表示日志消息,%n表示换行符 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern></encoder></appender><!-- 系统文件输出 --><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><!-- 日志输出级别 --><root level="ALL"><appender-ref ref="STDOUT" /><appender-ref ref="FILE" /></root>
</configuration>

 日志级别

日志级别指的是日志信息的类型,日志都会分级别,常见的日志级别如下(级别由低到高

 可以在配置文件中,灵活的控制输出哪些类型的日志。(大于等于配置的日志级别的日志才会输出

	<root level="debug"><appender-ref ref="STDOUT" /><appender-ref ref="FILE" /></root>

比如说我这里的等级是 debug,那么 trace 级别的日志就不会输出

 最后我们把 tlias Controller 层的 sout 换成 log.info即可

    //    System.out.println("查询全部部门的数据");log.info("查询全部部门的数据");

http://www.xdnf.cn/news/1120717.html

相关文章:

  • 纯CSS轮播
  • SAP ERP与微软ERP dynamics对比,两款云ERP产品有什么区别?
  • 【第零章编辑器开发与拓展】
  • 不用下载软件也能录屏?Windows 10 自带录屏功能详解
  • Postman、Apifox、Apipost用哪个? 每个的优缺点和综合比较(个人观点)
  • qt多线程的实战使用
  • 【记录】BLE|百度的旧蓝牙随身音箱手机能配对不能连接、电脑能连接不能使用的解决思路(Wireshark捕获并分析手机蓝牙报文)
  • Linux(Ubuntu)硬盘使用情况解析(已房子举例)
  • HTML面试题
  • 消费 Kafka 一个TOPIC数据,插入到另一个KAFKA的TOPIC
  • python学习2
  • ubuntu(22.04)系统上安装 MuJoCo
  • FRP Ubuntu 服务端 + MacOS 客户端配置
  • 微前端架构详解
  • 《C++初阶之STL》【泛型编程 + STL简介】
  • Nacos 技术研究文档(基于 Nacos 3)
  • 基于R语言的极值统计学及其在相关领域中的实践技术应用
  • 迅为八核高算力RK3576开发板摄像头实时推理测试 ppyoloe目标检测
  • 《亿级流量系统架构设计与实战》通用高并发架构设计 读场景
  • 文心4.5开源之路:引领技术开放新时代!
  • Go从入门到精通(22) - 一个简单web项目-统一日志输出
  • 如何单独安装设置包域名
  • LeetCode--45.跳跃游戏 II
  • 雷卯针对灵眸科技RV1106G3开发板防雷防静电方案
  • AI数字人正成为医药行业“全场景智能角色”,魔珐科技出席第24届全国医药工业信息年会
  • 2024年中国公交网络数据集(Shp/分城市)
  • 【DOCKER】-6 docker的资源限制与监控
  • 【机器学习深度学习】Ollama vs vLLM vs LMDeploy:三大本地部署框架深度对比解析
  • ElasticSearch重置密码
  • LabVIEW浏览器ActiveX事件交互