Javaweb-day10 案例
前面学习内容的总结 这部分完成一个web开发的综合案例
通过综合案例,掌握前端程序、后端程序、以及数据库三者是如何交互的
还需掌握根据接口文档开发服务端接口的能力
准备工作
需求&环境搭建
引入web开发的起步依赖、mybatis的相关依赖(两个依赖:mybatis的起步依赖、mysql的驱动)、再引入一个工具包lombok目的是简化实体类的定义
今晚是个小天才哈哈哈哈
前端开发前端工程,最终将打包好的前端工程部署在NGINX服务器上运行
~也就是服务端工程,~部署在tomcat服务器当中
接口文档是开发人员根据产品经理提供的页面原型和需求分析出来的
目前根据接口文档来开发功能接口
接口文档形式多种多样,在线yapi / 离线markdown,记事本
开发规范
先知道功能要做什么 (要实现什么样的效果)【明确需求】
根据页面原型以及需求定义表结构、定义接口文档
思路分析之后进行功能接口开发、接口测试、最后联合前端进行一个联调测试
部门管理
查询部门
【注意】:在进行项目开发的过程当中,尽量不要用sout输出日志
只需要加上一个注解@Slf4j
Logback框架记录日志详解
Logback
是一个高效且灵活的 Java 日志框架,广泛用于企业级应用中。它提供了丰富的配置选项和强大的日志记录功能。下面将详细介绍如何使用Logback
记录日志,包括配置文件的编写、日志记录的基本用法以及一些高级特性。1. 配置文件
Logback
的配置文件通常是logback.xml
,位于类路径的根目录下。配置文件使用 XML 格式,可以定义日志记录器、Appender、Layout 和 Filter 等。基本配置示例
<configuration> <!-- 定义一个 Console Appender --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 定义一个 File Appender --> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>logs/app.log</file> <encoder> <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern> </encoder> </appender> <!-- 定义一个 RollingFileAppender --> <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/rolling.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天滚动一次 --> <fileNamePattern>logs/rolling.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 保留30天的日志文件 --> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern> </encoder> </appender> <!-- 定义一个 Logger --> <logger name="com.example" level="DEBUG" additivity="false"> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </logger> <!-- 根 Logger --> <root level="INFO"> <appender-ref ref="STDOUT" /> <appender-ref ref="ROLLING_FILE" /> </root> </configuration>
2. 日志记录的基本用法
引入依赖
首先,确保你的项目中已经引入了
Logback
和SLF4J
的依赖。如果你使用 Maven,可以在pom.xml
中添加以下依赖:<dependencies> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.11</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.32</version> </dependency> </dependencies>
编写日志记录代码
在 Java 代码中,你可以使用
SLF4J
的LoggerFactory
获取一个Logger
实例,然后使用该实例记录日志。import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyApp { private static final Logger logger = LoggerFactory.getLogger(MyApp.class); public static void main(String[] args) { logger.debug("This is a debug message"); logger.info("This is an info message"); logger.warn("This is a warn message"); logger.error("This is an error message"); try { int result = 10 / 0; } catch (ArithmeticException e) { logger.error("An arithmetic exception occurred", e); } } }
3. 高级特性
日志级别
Logback
支持多种日志级别,包括TRACE
、DEBUG
、INFO
、WARN
和ERROR
。你可以在配置文件中设置每个Logger
的日志级别。<logger name="com.example" level="DEBUG" />
动态日志级别
你可以使用
JMX
或者Logback
提供的TurboFilter
动态调整日志级别。MDC(Mapped Diagnostic Context)
MDC
允许你在日志记录中添加上下文信息,例如用户 ID、请求 ID 等。import org.slf4j.MDC; public class MyApp { private static final Logger logger = LoggerFactory.getLogger(MyApp.class); public static void main(String[] args) { MDC.put("userId", "12345"); logger.info("Processing request for user"); MDC.remove("userId"); } }
在配置文件中,你可以使用
%X{userId}
来引用 MDC 中的值:<pattern>%date %level [%thread] %logger{10} [%file:%line] %X{userId} %msg%n</pattern>
异步日志记录
Logback
支持异步日志记录,可以通过Lombok
的@Slf4j
注解和Logback
的AsyncAppender
实现。<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="STDOUT" /> <appender-ref ref="ROLLING_FILE" /> </appender> <root level="INFO"> <appender-ref ref="ASYNC" /> </root>
4. 常见问题和最佳实践
配置文件加载顺序
Logback
会按照以下顺序查找配置文件:
logback-test.xml
logback.groovy
logback.xml
日志文件大小控制
使用
RollingFileAppender
可以控制日志文件的大小和数量。<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>logs/rolling.%i.log.zip</fileNamePattern> <minIndex>1</minIndex> <maxIndex>3</maxIndex> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>10MB</maxFileSize> </triggeringPolicy>
日志文件加密
如果你需要对日志文件进行加密,可以使用第三方工具或自定义
Appender
。总结
Logback
是一个功能强大且灵活的 Java 日志框架,通过合理的配置和使用,可以有效地管理和记录应用的日志信息。
@RequestMapping
是 Spring MVC 中的一个核心注解,用于映射 HTTP 请求到控制器方法。它可以应用于类级别和方法级别,以指定请求的 URL 路径、HTTP 方法类型、请求参数等。下面是对@RequestMapping
注解的详细解释。1. 基本用法
类级别的
@RequestMapping
在类级别使用
@RequestMapping
可以为整个控制器类指定一个公共的路径前缀。所有该类中的方法都会继承这个前缀。@Controller @RequestMapping("/users") public class UserController { @GetMapping("/{id}") public String getUser(@PathVariable Long id) { // 处理逻辑 return "userView"; } }
在这个例子中,
/users
是类级别的路径前缀,因此getUser
方法的实际路径是/users/{id}
。方法级别的
@RequestMapping
在方法级别使用
@RequestMapping
可以指定具体的请求路径和方法类型。@Controller public class UserController { @RequestMapping(value = "/users/{id}", method = RequestMethod.GET) public String getUser(@PathVariable Long id) { // 处理逻辑 return "userView"; } }
2. 属性详解
value
或path
指定请求的 URL 路径。这两个属性是等价的,可以互换使用。
@RequestMapping(value = "/users/{id}") @RequestMapping(path = "/users/{id}")
method
指定请求的方法类型,如
GET
、POST
、PUT
、DELETE
等。可以使用RequestMethod
枚举值。@RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
params
指定请求必须包含的参数。可以是具体的参数值或参数的存在性。
@RequestMapping(value = "/users", params = "action=view") @RequestMapping(value = "/users", params = {"action", "id"})
headers
指定请求必须包含的头信息。
@RequestMapping(value = "/users", headers = "Content-Type=application/json")
consumes
指定请求的内容类型。通常用于 POST 和 PUT 请求。
@RequestMapping(value = "/users", consumes = "application/json")
produces
指定响应的内容类型。通常用于 GET 请求。
@RequestMapping(value = "/users/{id}", produces = "application/json")
3. 简化注解
Spring MVC 提供了一些简化版的注解,它们是
@RequestMapping
的特化版本,用于更简洁地映射特定类型的请求:
@GetMapping
:等同于@RequestMapping(method = RequestMethod.GET)
@PostMapping
:等同于@RequestMapping(method = RequestMethod.POST)
@PutMapping
:等同于@RequestMapping(method = RequestMethod.PUT)
@DeleteMapping
:等同于@RequestMapping(method = RequestMethod.DELETE)
@PatchMapping
:等同于@RequestMapping(method = RequestMethod.PATCH)
示例
@RestController @RequestMapping("/api") public class UserController { @GetMapping("/users/{id}") public User getUser(@PathVariable Long id) { // 处理逻辑 return userService.getUserById(id); } @PostMapping("/users") public User createUser(@RequestBody User user) { // 处理逻辑 return userService.createUser(user); } @PutMapping("/users/{id}") public User updateUser(@PathVariable Long id, @RequestBody User user) { // 处理逻辑 return userService.updateUser(id, user); } @DeleteMapping("/users/{id}") public void deleteUser(@PathVariable Long id) { // 处理逻辑 userService.deleteUser(id); } }
总结
@RequestMapping
是一个强大的注解,用于将 HTTP 请求映射到控制器方法。通过类级别和方法级别的组合使用,可以灵活地管理请求路径和方法类型。Spring MVC 还提供了多个特化版本的注解,使代码更加简洁和易读。
在postman里面获取到的是一个json格式的数据,是result转的结果
因为在Controller层加了一个注解@RestController,其是组合注解,包含了responsebody会将返回值当中的对象直接转为json再响应回来
三层架构实现查询部门【!!!】
import com.wujiao.pojo.Dept;
import com.wujiao.pojo.Result;
import com.wujiao.service.DeptService;
import lombok.extern.slf4j.Slf4j;
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;
@Slf4j
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
//@RequestMapping(value = "/depts",method= RequestMethod.GET)
@GetMapping("/depts")
public Result list(){
log.info("查询全部部门数据");
List<Dept> deptList= deptService.list();
return Result.success(deptList);
}
}
import com.wujiao.pojo.Dept;
import java.util.List;
public interface DeptService {
//查询全部部门数据
List<Dept> list();
}
import com.wujiao.mapper.DeptMapper;
import com.wujiao.pojo.Dept;
import com.wujiao.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public List<Dept> list() {
return deptMapper.list();
}
}
import com.wujiao.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface DeptMapper {
@Select("select * from dept")
List<Dept> list();
}
前后端联调
指的是将前端工程、后端工程都启动起来,然后访问前端工程,通过访问前端工程来访问服务端程序,进而进行调试
访问不出来那个页面,可能是因为没有配置前端环境 后面再回顾一下前面那块
nginx碎了什么办法都试了 算了之后再看
啊啊啊啊出来了 虽然不知道原理为啥
代表的是请求的是nginx服务器,被nginx服务器接收到这次请求之后,最终nginx会把这个请求转给后端的8080端口的tomcat,实际上是由tomcat处理的这次请求
删除部门
问题1:怎么在controller中接收请求路径中的路径参数?
@PathVariable问题2:如何限定请求方式是delete?
@DeleteMapping
@PathVariable
是 Spring MVC 框架中用于从 URL 中提取变量值的注解。它允许开发者通过方法参数直接获取请求路径中的动态部分。这种技术在 RESTful API 设计中非常有用,因为可以创建更加清晰和直观的 URL。使用场景
当你需要根据 URL 中的一部分来处理请求时,比如获取某个用户的详细信息,可以使用
@PathVariable
。例如,URL 可能看起来像这样:/users/{id}
,其中{id}
就是一个路径变量。示例代码
假设你有一个用户管理的应用程序,想要通过用户的 ID 来获取用户信息,可以这样做:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @GetMapping("/users/{id}") public String getUserById(@PathVariable("id") String userId) { // 假设这里进行数据库查询等操作 return "User details for user: " + userId; } }
在这个例子中,
@PathVariable("id")
注解告诉 Spring 框架将 URL 路径中的{id}
部分绑定到方法参数userId
上。多个路径变量
如果一个方法需要从路径中提取多个变量,也可以轻松实现:
@GetMapping("/articles/{articleId}/comments/{commentId}") public String getComment(@PathVariable String articleId, @PathVariable String commentId) { return "Article ID: " + articleId + ", Comment ID: " + commentId; }
这里,
@PathVariable
分别用来提取文章 ID 和评论 ID。类级别的
@PathVariable
如果你希望在整个控制器类中都能访问某个路径变量,可以在类级别使用
@PathVariable
注解,但这不是常见的用法,通常我们都是在方法参数上使用它。注意事项
- 当使用
@PathVariable
时,确保路径中的变量名与方法参数上的注解名称相匹配,除非你在注解中指定了名称。- 如果路径变量的类型是数字(如
int
,long
),Spring 会自动尝试转换类型。如果转换失败,会抛出异常。- 对于复杂的路径模式,可能需要考虑使用正则表达式来限制路径变量的格式。
总之,
@PathVariable
是构建灵活且可读性高的 RESTful API 的一个重要工具。
新增部门
接口文档规定:
前端请求路径:/depts
前端请求方式:POST
前端请求参数 (Json格式):{ "name": "教研部" }
问题1:如何限定请求方式是POST?
@PostMapping问题2:怎么在controller中接收json格式的请求参数?
@RequestBody //把前端传递的json数据填充到实体类中修改部门
一个完整的请求路径,是类上的@RequestMapping的value属性+方法上的@Request Mapping的value属性
修改部门
1.根据ID查询2.修改部门
四个部门管理的接口实现代码
DeptController
package com.wujiao.controller;
import com.wujiao.pojo.Dept;
import com.wujiao.pojo.Result;
import com.wujiao.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/depts")
public class DeptController {
@Autowired
private DeptService deptService;
//@RequestMapping(value = "/depts",method= RequestMethod.GET)
// 查询部门数据
@GetMapping
public Result list(){
log.info("查询全部部门数据");
List<Dept> deptList= deptService.list();
return Result.success(deptList);
}
// 删除部门
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id){
log.info("根据id删除部门:{}",id);
deptService.delete(id);
return Result.success();
}
// 新增部门
@PostMapping
public Result add(@RequestBody Dept dept){
log.info("新增部门:{}",dept);
deptService.add(dept);
return Result.success();
}
// 修改部门
@GetMapping("/{id}")
public Result selectByid(@PathVariable Integer id){
Dept d = deptService.selectById(id);
return Result.success(d);
}
@PutMapping()
public Result edit(@RequestBody Dept dept){
log.info("新增部门:{}",dept);
deptService.edit(dept);
return Result.success();
}
}
DeptService
package com.wujiao.service;
import com.wujiao.pojo.Dept;
import java.util.List;
public interface DeptService {
//查询全部部门数据
List<Dept> list();
//删除部门
void delete(Integer id );
//新增部门
void add(Dept dept);
//修改部门
void edit(Dept dept);
//查询要修改的部门
Dept selectById(Integer id);
}
DeptServiceImpl
package com.wujiao.service.impl;
import com.wujiao.mapper.DeptMapper;
import com.wujiao.pojo.Dept;
import com.wujiao.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public List<Dept> list() {
return deptMapper.list();
}
@Override
public void delete(Integer id) {
deptMapper.deleteById(id);
}
@Override
public void add(Dept dept) {
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
deptMapper.insert(dept);
}
@Override
public Dept selectById(Integer id){
return deptMapper.select(id);
}
@Override
public void edit(Dept dept){
dept.setUpdateTime(LocalDateTime.now());
deptMapper.edit(dept);
}
}
DeptMapper
package com.wujiao.mapper;
import com.wujiao.pojo.Dept;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface DeptMapper {
// 查询全部部门
@Select("select * from dept")
List<Dept> list();
// 根据ID删除部门
@Delete("delete from dept where id = #{id}")
void deleteById(Integer id);
// 新增部门
@Insert("insert into dept(name,create_time,update_time)values(#{name},#{createTime},#{updateTime})")
void insert(Dept dept);
// 修改部门
@Select("select * from dept where id=#{id}")
Dept select(Integer id);
@Update("update dept set name=#{name},update_time=#{updateTime} where id=#{id}")
void edit(Dept dept);
}
员工管理
分页查询
复习一下Mysql里面的分页查询语句
select * from emp limit 0,5;
参数1:起始索引
参数2:查询返回记录数=每页展示记录数
开始索引的计算公式: 开始索引 = (当前页码 - 1) * 每页显示条数
获取总记录数
select count (*) from emp;
-
前端在请求服务端时,传递的参数
-
当前页码 page
-
每页显示条数 pageSize
-
-
后端需要响应什么数据给前端
-
所查询到的数据列表(存储到List 集合中)
-
总记录数
-
@RequestParam(defaultValue="默认值") //设置请求参数默认值
分页插件
分页插件帮我们完成了以下操作:
-
先获取到要执行的SQL语句:select * from emp
-
把SQL语句中的字段列表,变为:count(*)
-
执行SQL语句:select count(*) from emp //获取到总记录数
-
再对要执行的SQL语句:select * from emp 进行改造,在末尾添加 limit ? , ?
-
执行改造后的SQL语句:select * from emp limit ? , ?
当使用了PageHelper分页插件进行分页,就无需在Mapper中进行手动分页了。 在Mapper中我们只需要进行正常的列表查询即可。在Service层中,调用Mapper的方法之前设置分页参数,在调用Mapper方法执行查询之后,解析分页结果,并将结果封装到PageBean对象中返回。
分页查询(带条件)
EmpMapper
package com.wujiao.mapper;
import com.wujiao.pojo.Emp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDate;
import java.util.List;
@Mapper
public interface EmpMapper {
查询总记录数
// @Select("select count(*) from emp")
// public Long count();
//
分页查询,获取列表数据
// @Select("select * from emp limit #{start},#{pageSize}")
// public List<Emp> list(Integer start,Integer pageSize);
public List<Emp> list(String name,Short gender,LocalDate begin,LocalDate end);
}
记得xml文件就是动态SQL语句,所以一定要删@Select语句!卡我半小时气人
EmpMapper.xml
<?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.wujiao.mapper.EmpMapper">
<!-- 条件分页查询 -->
<select id="list" resultType="com.wujiao.pojo.Emp">
select * from emp
<where>
<if test="name != null and name != ''">
name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
</mapper>
EmpController
package com.wujiao.controller;
import com.wujiao.pojo.PageBean;
import com.wujiao.pojo.Result;
import com.wujiao.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
@Autowired
private EmpService empService;
// 条件分页查询
@GetMapping
public Result page(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize,
String name, Short gender,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
log.info("分页查询,参数:{},{},{},{},{},{}",page,pageSize,name,gender,begin,end);
PageBean pageBean = empService.page(page,pageSize,name,gender,begin,end);
return Result.success(pageBean);
}
}
EmpService
package com.wujiao.service;
import com.wujiao.pojo.PageBean;
import java.time.LocalDate;
public interface EmpService {
/*
* 条件分页查询
*/
PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin,LocalDate end);
}
EmpServiceImpl
package com.wujiao.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wujiao.mapper.EmpMapper;
import com.wujiao.pojo.Emp;
import com.wujiao.pojo.PageBean;
import com.wujiao.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List;
@Service//代表将当前这个实现类交给IOC容器管理,成为容器中的bean对象
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
/*@Override
public PageBean page(Integer page, Integer pageSize) {
Long count = empMapper.count();//获取总记录数
//获取分页查询结果列表
Integer start = (page-1)*pageSize;
List<Emp> empList = empMapper.list(start,pageSize);
//封装PageBean对象
PageBean pageBean = new PageBean(count,empList);
return pageBean;
}*/
public PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end){
// 设置分页参数
PageHelper.startPage(page,pageSize);
// 执行分页查询
List<Emp> empList = empMapper.list(name,gender,begin,end);
// 获取分页结果
Page<Emp> p= (Page<Emp>) empList;
//封装PageBean对象
PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
return pageBean;
}
}
在进行接口测试和前后端联调中,尽量测试的全面一些,覆盖所有的情况
好处:在测试阶段将所有的bug暴露出来,进而对功能接口进行完善修复
删除员工
如果有人被气鼠的话一定是我!!!!先是没删@Select语句,又是没看清楚请求路径忘记加s
好好好我的一个半小时
原文地址:https://blog.csdn.net/wujiao__11/article/details/143577909
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!