
环境搭建
- 准备数据库表(dept,emp)
- 创建springboot工程,引入对应的起步依赖
- 配置文件application.properties 中引入mybatis的配置信息,准备对应的实体类
- 准备对应的Mapper,Service(接口,实现类),Controller基础结构
项目结构
配置文件
编写规范
- 基本信息
- 请求路径
- 请求方式
- 接口描述
- 接收参数
- 响应数据
- 参数含义
- 响应数据的案例(json的格式)
Restful - 开发规范
- REST(REpresentational State Transfer),表述性状态转换,它是一种软甲架构风格
- URL定位资源
- HTTP动词描述操作
- REST 是风格,是约定方式,约定不是规定,可以打破。
- 描述模块的功能通常使用复数,也就是加 s 的格式来描述,表示此类资源,而非单个资源。如:users、emps、books...
java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code; // 响应码,1 代表成功;0 代表失败
private String msg; // 响应信息 描述字符串
private Object data; // 返回的数据
public static Result success() { // 增删改 成功响应
return new Result(1, "success", null);
}
public static Result success(Object data) { // 查询 成功响应
return new Result(1, "success", data);
}
public static Result error(String msg) { // 失败响应
return new Result(0, msg, null);
}
}
- 查看页面原型,明确需求
- 阅读接口文档
- 思路分析
- 接口开发
- 接口测试
- 前后端联调
日志记录
java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
log .info("user");
labok
中为注解提供了一种注解 @Slf4j --> 然后就可以之直接使用 log
注: @RestController 注解中包含了一个 @ResponseBody --> 可以将返回对象直接返回为json对象
个人梳理:
- Controller中写入一个 service 层 的接口 ,底层会自动将该接口实例化
- 然后调用 service 层的方法
- 同样的方式进入 mapper 层
解决跨域问题
- 后端实现
java
// 全局配置类
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有接口
.allowedOrigins("http://localhost:3000", "http://your-domain.com") // 允许的源
.allowedMethods("*") // GET/POST等
.allowedHeaders("*") // 请求头
.allowCredentials(true) // 允许带cookie
.maxAge(3600); // 预检请求缓存时间
}
}
这段 Java 代码定义了一个名为CorsConfig
的全局配置类,用于解决跨域资源共享(CORS)问题,以下是对该类各部分作用的详细解析:
1. 类声明及实现接口
java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Configuration
是 Spring 框架中的一个注解,用于标记该类是一个配置类,Spring 容器会扫描并加载该类中的配置信息。
CorsConfig
类实现了 WebMvcConfigurer
接口,通过实现这个接口,可以自定义 Spring MVC 的配置,这里主要用于配置 CORS 相关的信息。
2. addCorsMappings
方法
java
@Override
public void addCorsMappings(CorsRegistry registry) {
addCorsMappings
方法是 WebMvcConfigurer
接口中的一个方法,通过重写这个方法来配置 CORS 策略。CorsRegistry
是 Spring 提供的一个用于注册 CORS 映射的类,通过它可以定义哪些请求路径适用 CORS 配置,以及具体的 CORS 配置项。
3. 配置 CORS 具体策略
java
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000", "http://your-domain.com")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
addMapping("/**")
:表示对所有的接口(路径)都应用 CORS 配置。"/**"
是一个通配符,匹配所有请求路径。.allowedOrigins("http://localhost:3000", "http://your-domain.com")
:设置允许访问该后端服务的源(origin)。这里指定了两个源,http://localhost:3000
和http://your-domain.com
,只有来自这两个源的请求会被允许跨域访问。如果需要允许所有源,可以使用"*"
,但这样存在安全风险,不建议在生产环境中使用。.allowedMethods("*")
:设置允许的 HTTP 方法,这里"*"
表示允许所有的 HTTP 方法,如 GET、POST、PUT、DELETE 等。也可以具体指定,例如".allowedMethods("GET", "POST")"
。.allowedHeaders("*")
:设置允许在请求头中携带的字段,"*"
表示允许所有请求头字段。同样,也可以具体指定允许的请求头字段。.allowCredentials(true)
:设置是否允许携带 Cookie 等认证信息。设置为true
表示允许在跨域请求中携带 Cookie,前提是请求的源在allowedOrigins
中明确列出,因为不能对*
源启用该功能。.maxAge(3600)
:设置预检请求(OPTIONS 请求)的缓存时间,单位是秒。在缓存时间内,浏览器不会再次发送预检请求,而是直接使用缓存中的 CORS 配置,从而提高性能。
总的来说,这个 CorsConfig
类通过上述配置,使得 Spring Boot 应用能够支持跨域请求,并且对跨域请求的源、方法、请求头、是否允许携带认证信息以及预检请求缓存等方面进行了详细的设置。
js
// 在 vue.config.js 中配置
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080', // 后端地址
changeOrigin: true,
pathRewrite: { '^/api': '' } // 去掉路径中的/api
}
}
}
}
前端获取数据
js
fetchUsers() {
fetch('/api/user')
.then(response => response.json())
.then(data => {
this.users = data.data;
})
.catch(error => {
console.error(error);
});
},
- 将得到的数据返回
json
格式 - 然后就可以通过
json
方式访问到数据
简化Mapping层的代码

mapper层的SQL写法
java
@Update("UPDATE learn01 SET name=#{name},age=#{age} WHERE id=#{id}")
void edit(User user);
事件总线
- 创建一个空的 Vue 实例作为 "总线"(全局唯一)
- 发送方组件通过
bus.$emit('事件名', 数据)
发送事件 - 接收方组件通过
bus.$on('事件名', 回调函数)
监听事件 - 回调函数中可以处理接收到的数据或执行相应方法
- 组件销毁前需通过
bus.$off('事件名')
移除监听,避免内存泄漏
登录
- 登录功能
- 登录校验
- 会话技术
- JWT令牌
- 过滤器 Filter
- 拦截器 Interceptor
- 异常处理
会话技术
会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应
会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据
- 客户端会话跟踪技术:Cookie
- 优点:HTTP协议中支持的技术
- 缺点
- 移动端APP无法使用Cookie
- 不安全,用户可以自己警用Cookie
- Cookie不能跨域
- 服务端会话跟踪技术:Session
- 优点:存储在服务端,安全
- 缺点
- 服务器集群环境下无法直接使用Session
- Cookie的缺点
- 令牌技术
- 优点
- 支持PC端,移动端
- 解决集群环境下的认证问题
- 减轻服务器端存储压力
- 缺点:需要自己来实现
- 优点
JWT(JSON Web Token)
简介
定义了一种简洁的,自包含的格式,用于在通信双方以json数据格式安全的传输信息,由于数字签名的存在,这些信息是可靠的
- 组成
- 第一部分:Header, 记录令牌类型,签名算法
- 第二部分:Payload(有效荷载),携带一些自定义信息,默认信息
- 第三部分:Signature(签名),防止Token被篡改,保证安全性,将header,payload,并加入指定密钥,通过指定签名算法计算而来
JWT生成
配置依赖项
xml
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<!-- JJWT 实现 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<!-- JJWT JSON 处理器 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
java
@Test
void getJwt(){
Map<String,Object> map = new HashMap<>();
map.put("id","1");
map.put("username","admin");
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
String jwt = Jwts.builder()
.setClaims(map)
.signWith(SignatureAlgorithm.HS256,key)
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
.compact();
System.out.println(jwt);
Claims claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(jwt)
.getBody();
System.out.println(claims);
}
Filter过滤器
- 概念:Filter 过滤器,是JavaWeb三大组件之一
- 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能
- 过滤器一般完成一些通用的操作:登录校验,同一编码处理,敏感字符处理等
- 快速入门
- 详解
- 登录校验
快速入门
- 定义Filter:定义一个类,实现Filter接口,并重写其所有方法
- 配置Filter:Filter类上加
@WebFilter
注解,配置拦截资源的路径。引导类上加@ServletComponentScan
开启Servlet组件支持
java
public class DemoFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException { //初始化方法, Web服务器启动, 创建Filter时调用, 只调用一次
Filter.super.init(filterConfig);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) //拦截到请求时, 调用该方法, 可调用多次
System.out.println("拦截方法执行,拦截到了请求 ...");
chain.doFilter(request, response); //放行
sout("放行之后的逻辑");
}
}
拦截路径 | urlPatterns 值 | 含义 |
---|---|---|
拦截具体路径 | /login | 只有访问 /login 路径时,才会被拦截 |
目录拦截 | /emps/* | 访问 /emps 下的所有资源,都会被拦截 |
拦截所有 | /* | 访问所有资源,都会被拦截 |
过滤器链

顺序:注解配置恶的Filter,优先级是按照过滤器类名(字符串)的自然顺序
登录校验
- 获取请求 url。
- 判断请求 url 中是否包含 login,如果包含,说明是登录操作,放行。
- 获取请求头中的令牌(token)。
- 判断令牌是否存在,如果不存在,返回错误结果(未登录)。
- 解析 token,如果解析失败,返回错误结果(未登录)。
- 放行。
将对象转换成json格式 引入的依赖
xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
java
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//1.获取请求url。
String url = req.getRequestURL().toString();
log.info("请求的url: {}",url);
//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行。
if(url.contains("login")){
log.info("");
}
//3.获取请求头中的令牌(token)。
String jwt = req.getHeader("token");
//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。
if(!StringUtils.hasLength(jwt)){
log.info("请求头token为空,返回未登录的信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 对象--json -------> 阿里巴巴fastJSON
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return;
}
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) { //jwt解析失败
e.printStackTrace();
log.info("解析令牌失败,返回未登录错误信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 对象--json -------> 阿里巴巴fastJSON
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return;
}
//6.放行。
log.info("令牌合法,放行");
chain.doFilter(request, response);
}
拦截器(Interceptor)
概念:是一种动态拦截方法调用的机制,类似于过滤器。spring框架中提供的,用来动态拦截控制器方法的执行
作用:拦截请求,在指定的方法调用前后,更具业务需求执行预定设定的代码
- 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法
- 注册拦截器
java
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override //目标资源方法执行前执行,放回true: 放行,返回false: 不放行
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
System.out.println("preHandle ...");
return true;
}
@Override //目标资源方法执行后执行
public void postHandle(HttpServletRequest req, HttpServletResponse resp, Object handler, ModelAndView modelAndView) {
System.out.println("postHandle ...");
}
@Override // 视图渲染完毕后运行
public void afterCompletion(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex) {
System.out.println("afterCompletion ...");
}
}
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
}
}
详解
拦截路径 | 含义 | 举例 |
---|---|---|
/* |
一级路径 | 能匹配/depts ,/emps ,/login ,不能匹配 /depts/1 |
/** |
任意级路径 | 能匹配/depts ,/depts/1 ,/depts/1/2 |
/depts/* |
/depts 下的一级路径 |
能匹配/depts/1 ,不能匹配/depts/1/2 ,/depts |
/depts/** |
/depts 下的任意级路径 |
能匹配/depts ,/depts/1 ,/depts/1/2 ,不能匹配/emps/1 |
java
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
// 需要拦截哪些资源 不需要拦截哪些资源

Filter 与 Interceptor 之间的区别
- 接口规范不同:过滤器需要实现 Filter 接口,而拦截器需要实现 HandlerInterceptor 接口
- 拦截范围不同:过滤器 Filter 会拦截所有的资源,而 Interceptor 只会拦截 Spring 环境中的资源
异常处理
全局异常处理器
遇到异常时的处理逻辑:
Mapper --> Service --> Controller --> 全局异常处理器
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error(" 对不起,操作失败,请联系管理员 ");
}
}