目录
一.导入
什么是SSM框架?
1.Spirng框架
Spring 是一个轻量级的 Java 开发框架
核心特性:
IoC(控制反转)
通过 XML 配置或注解,将对象的创建和依赖关系管理交给 Spring 容器,减少代码耦合示例:
@Service public class UserServiceImpl implements UserService { @Autowired // 自动注入依赖 private UserDao userDao; }
AOP(面向切面编程)
通过代理模式实现横切关注点(如日志、事务)的统一管理,避免代码重复。
2.SpirngMVC
Spring MVC 是 Java 企业级开发中最流行的 Web 框架之一,它基于 MVC(Model-View-Controller)架构模式
二.项目介绍
项目源码:blog-system: 我的博客系统
“悟空博客” 是一款基于 SSM(Spring + Spring MVC + MyBatis)框架开发的博客平台,旨在为用户提供便捷的内容创作与分享空间
(一)项目功能
本项目围绕博客系统展开,涉及注册、登录、博客列表展示、博客详情查看、博客编写等功能:
- 注册页面:提供用户名、密码及确认密码输入框,用户可在此完成注册操作,点击提交后跳转至登录页面。
- 登录页面:设有用户名和密码输入框,用户输入已在后端数据库存储的账号信息,点击提交后,若验证通过,将跳转至列表页面。
- 博客列表页面:展示已发布博客的标题、发布时间和内容概要,每篇博客旁有查看全文、修改、删除操作按钮。左侧呈现登录用户信息及文章数、分类数。右上角有主页(即当前列表页)、写博客、注销功能,可进行相应页面跳转。
- 博客详情页面:显示单篇博客完整内容,以及发布时间、阅读量等信息。
- 博客编辑页面:具备富文本编辑功能,用户可输入文章标题,在编辑区域撰写博客内容,完成后点击提交可发布博客,发布成功后跳转至列表页面
(二)页面展示
1.注册页面
2.登录页面
3.列表页面
4.详情页面
5.编辑页面
三.准备工作
数据库表
1.用户表——userinfo
CREATE TABLE userinfo (
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
username varchar(100) NOT NULL,
password varchar(65) NOT NULL,
photo varchar(500),
createtime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
updatetime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
state int(11) DEFAULT 1
);
2.文章表——articleinfo
CREATE TABLE articleinfo (
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
title varchar(100) NOT NULL,
content text NOT NULL,
createtime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
updatetime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
uid int(11) NOT NULL,
rcount int(11) DEFAULT 1,
state int(11) DEFAULT 1
);
3.插入数据
INSERT INTO userinfo (username, password)
VALUES
("Wukong.Sun", "111111"),
("w_o.ogason", "123456");
四.创建项目
1.创建SpringBoot项目
添加Spring MVC 和MyBatis对应依赖
2.创建对应目录
3.准备前端页面
把博客系统静态⻚⾯拷⻉到static⽬录下
4.配置配置文件
server:
port: 7070
spring:
jackson:
date-format: 'yyyy-MM-dd HH:mm:ss'
time-zone: 'GMT+8'
datasource:
url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8
username: root
password: 111111
driver-class-name: com.mysql.cj.jdbc.Driver
# 开启 MyBatis SQL 打印
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 设置日志级别
logging:
level:
com:
example:
demo: debug
# 对具体类机型日志级别设定
五.项目公共模块
项⽬分为控制层(Controller), 服务层(Service), 持久层(Mapper). 各层之间的调⽤关系如下
公共层——common 包
我们先根据需求完成公共层代码的编写
1.AjaxResult类
前后端交互 响应结果类,用于封装 HTTP 请求的 返回的响应数据
返回统一格式的响应数据
@Data
(来自 Lombok):自动生成getter
、setter
、toString
等方法,简化代码。implements Serializable
:实现序列化接口,确保该类实例可在网络传输或存储中使用
/**
* 前后端交互响应结果类,用于封装 HTTP 请求的返回数据
* 返回统一格式的响应数据
* 在控制层(Controller)中使用
*/
@Data
public class AjaxResult implements Serializable {
// 状态码(如 200 成功,500 服务器错误)
private Integer code;
// 状态码的描述信息(如 "操作成功"、"参数错误")
private String msg;
// 返回的具体数据(如用户信息、列表数据等,可为 null)
private Object data;
/**
* 成功响应方法
* 接口处理请求成功时调用
*/
// 方法 1:默认状态码 200,无描述信息,带数据
public static AjaxResult success(Object data) {
AjaxResult result = new AjaxResult();
result.setCode(200);
result.setMsg("");
result.setData(data);
return result;
}
// 方法 2:自定义状态码,无描述信息,带数据
public static AjaxResult success(int code, Object data) {
AjaxResult result = new AjaxResult();
result.setCode(code);
result.setMsg("");
result.setData(data);
return result;
}
// 方法 3:自定义状态码、描述信息和数据
public static AjaxResult success(int code, String msg, Object data) {
AjaxResult result = new AjaxResult();
result.setCode(code);
result.setMsg(msg);
result.setData(data);
return result;
}
/**
* 失败响应方法
* 返回失败结果
* 接口处理请求失败时调用
*/
// 方法 1:自定义状态码、描述信息,无数据(推荐)
public static AjaxResult fail(int code, String msg) {
AjaxResult result = new AjaxResult();
result.setCode(code);
result.setMsg(msg);
result.setData(null);
return result;
}
// 方法 2:自定义状态码、描述信息和数据(较少用)
public static AjaxResult fail(int code, String msg, Object data) {
AjaxResult result = new AjaxResult();
result.setCode(code);
result.setMsg(msg);
result.setData(data);
return result;
}
}
2.PasswordUtils类
用于:对密码进行加密、验证
目的:通过 加盐(Salt)+ 哈希(MD5) 的方式增强密码安全
public class PasswordUtils {
/**
* 1.加盐并生成密码
*
* @param password 明文密码
* @return 保存到数据库中的密码
*/
public static String encrypt(String password) {
// 1.产生盐值(32位)
String salt = UUID.randomUUID().toString().replace("-", "");
// 2.生成加盐之后的密码
String saltPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
// 3.生成最终密码(保存到数据库中的密码)【约定格式:32位盐值+$+32位加盐之后的密码】
String finalPassword = salt + "$" + saltPassword;
return finalPassword;
}
/**
* 2.生成加盐的密码(方法1的重载)
*
* @param password 明文
* @param salt 固定的盐值
* @return 最终密码
*/
public static String encrypt(String password, String salt) {
// 1.生成一个加盐之后的密码
String saltPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
// 2.生成最终的密码【约定格式:32位盐值+$+32位加盐之后的密码】
String finalPassword = salt + "$" + saltPassword;
return finalPassword;
}
/**
* 3.验证密码
*
* @param inputPassword 用户输入的明文密码
* @param finalPassword 数据库保存的最终密码
* @return
*/
public static boolean check(String inputPassword, String finalPassword) {
if (StringUtils.hasLength(inputPassword) && StringUtils.hasLength(finalPassword) &&
finalPassword.length() == 65) {
// 1.得到盐值
String salt = finalPassword.split("\\$")[0];
// 2.使用之前加密的步骤,将明文密码和已经得到的盐值进行加密,生成最终的密码
String confirmPassword = PasswordUtils.encrypt(inputPassword, salt);
// 3.对比两个最终密码是否相同
return confirmPassword.equals(finalPassword);
}
return false;
}
}
3.UserSessionUtils类
用于:从 HTTP 请求中获取当前登录用户的信息。用户登录后通常会将用户信息存储在 HTTP Session(会话) 中
/**
* 从 HTTP 请求中获取当前登录用户的信息
*/
public class UserSessionUtils {
/**
* 通过静态方法直接获取当前登录用户,避免在代码中重复编写 Session 操作代码
*/
public static Userinfo getUser(HttpServletRequest request) {
// 1. 获取当前请求的 Session(不创建新 Session)
HttpSession session = request.getSession(false);
//2. 校验 Session 是否存在且包含用户信息
if (session != null &&
session.getAttribute(AppVariable.USER_SESSION_KEY) != null) {
// 3. 类型转换并返回用户信息对象
return (Userinfo) session.getAttribute(AppVariable.USER_SESSION_KEY);
}
return null;
}
}
4.AppVariable类
常量类:AppVariable.USER_SESSION_KEY
:一个常量字符串
作为:用户信息在 Session 中的唯一标识。
/**
*
*/
public class AppVariable {
// 用户 session key
public static final String USER_SESSION_KEY = "USER_SESSION_KEY";
}
六.业务代码
(一)实体类——entity包
1.Userinfo类
用于:封装用户信息 为一个对象
@Data
public class Userinfo {
private Integer id;
private String username;
private String password;
private String photo;
private LocalDateTime createtime;
private LocalDateTime updatetime;
private Integer state;
}
2.Articleinfo类
用于:封装文章信息
@Data
public class Articleinfo {
private Integer id;//文章ID 主键
private String title;
private String content;
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private LocalDateTime createtime;
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private LocalDateTime updatetime;
private Integer uid; //用户 ID(外键,关联作者)
private Integer rcount;
private Integer state;
}
3.UserinfoVO类
值对象,继承自 Userinfo
并增加“文章总数”字段
@Data
public class UserinfoVO extends Userinfo {
private Integer artCount; // 此人发表的文章总数
}
(二)持久层——mapper包
MyBatis
- 简介:Java 持久层框架,用于灵活操作数据库
- 应用场景:例如本次项目—在用户/文章管理模块中,使用 MyBatis 可以方便地实现用户/文章信息的增删改查
1.UserMapper接口
是一个基于 MyBatis 的用户数据访问接口
配合 MyBatis 等持久层框架,实现 Java 对象与数据库表的字段映射,从而操作 userinfo
表
是持久层框架—MyBaits里提供的一个接口注解。接口上标注了这个注解,就可以和xml映射文件关联起来。从而通过调用接口方法 实现对数据库表的增删查改。(xml文件中具体实现了接口里定义的方法)
@Mapper
public interface UserMapper {
// 注册
int reg(Userinfo userinfo);
// 根据用户查询 userinfo 对象
Userinfo getUserByName(@Param("username") String username);
Userinfo getUserById(@Param("id") Integer id);
}
2.AriticleMapper接口
是一个基于 MyBatis 的 文章数据访问接口,用于操作 articleinfo
表
@Mapper
public interface ArticleMapper {
int getArtCountByUid(@Param("uid") Integer uid);
List<Articleinfo> getMyList(@Param("uid") Integer uid);
int del(@Param("id") Integer id, @Param("uid") Integer uid);
Articleinfo getDetail(@Param("id") Integer id);
int incrRCount(@Param("id") Integer id);
int add(Articleinfo articleinfo);
int update(Articleinfo articleinfo);
List<Articleinfo> getListByPage(@Param("psize") Integer psize,
@Param("offsize") Integer offsize);
int getCount();
}
3.实现xml映射文件
用于实现 ArticleMapper/
UserMapper接口中定义的方法
<?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.example.demo.mapper.ArticleMapper">
<select id="getArtCountByUid" resultType="Integer">
select count(*) from articleinfo where uid=#{uid}
</select>
<select id="getMyList" resultType="com.example.demo.entity.Articleinfo">
select * from articleinfo where uid=#{uid}
</select>
<delete id="del">
delete from articleinfo where id=#{id} and uid=#{uid}
</delete>
<select id="getDetail" resultType="com.example.demo.entity.Articleinfo">
select * from articleinfo where id=#{id}
</select>
<update id="incrRCount">
update articleinfo set rcount=rcount+1 where id=#{id}
</update>
<insert id="add">
insert into articleinfo(title,content,uid) values(#{title},#{content},#{uid})
</insert>
<update id="update">
update articleinfo set title=#{title},content=#{content},updatetime=#{updatetime}
where id=#{id} and uid=#{uid}
</update>
<select id="getListByPage" resultType="com.example.demo.entity.Articleinfo">
select * from articleinfo limit #{psize} offset #{offsize}
</select>
<select id="getCount" resultType="Integer">
select count(*) from articleinfo
</select>
</mapper>
<?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.example.demo.mapper.UserMapper">
<insert id="reg">
insert into userinfo(username,password) values(#{username},#{password})
</insert>
<select id="getUserByName" resultType="com.example.demo.entity.Userinfo">
select * from userinfo where username=#{username}
</select>
<select id="getUserById" resultType="com.example.demo.entity.Userinfo">
select * from userinfo where id=#{id}
</select>
</mapper>
(三)服务层——service包
负责处理业务逻辑
关键注解:
1. @Service
2. @Resource
1.UserService类
负责处理用户相关的业务逻辑
@Service
public class UserService {
@Resource
private UserMapper userMapper;
public int reg(Userinfo userinfo) {
return userMapper.reg(userinfo);
}
public Userinfo getUserByName(String username) {
return userMapper.getUserByName(username);
}
public Userinfo getUserById(Integer id) {
return userMapper.getUserById(id);
}
}
2.ArticleService类
负责处理文章相关的业务逻辑
@Service
public class ArticleService {
@Resource
private ArticleMapper articleMapper;
public int getArtCountByUid(Integer uid) {
return articleMapper.getArtCountByUid(uid);
}
//获取当前用户的文章列表
public List<Articleinfo> getMyList(Integer uid) {
return articleMapper.getMyList(uid);
}
//删除文章
public int del(Integer id, Integer uid) {
return articleMapper.del(id, uid);
}
//获取文章详情
public Articleinfo getDetail(Integer id) {
return articleMapper.getDetail(id);
}
//增加文章阅读量
public int incrRCount(Integer id) {
return articleMapper.incrRCount(id);
}
//增加文章
public int add(Articleinfo articleinfo) {
return articleMapper.add(articleinfo);
}
//更新文章
public int update(Articleinfo articleinfo) {
return articleMapper.update(articleinfo);
}
public List<Articleinfo> getListByPage(Integer psize, Integer offsize) {
return articleMapper.getListByPage(psize, offsize);
}
public int getCount() {
return articleMapper.getCount();
}
}
(四)控制层——controller
负责处理HTTP请求
SpringMVC中的核心组件:
关键注解:
1.@RestControlelr
2.@RequestMapping
3.@AutoWired
1.UserController类
负责处理用户相关的HTTP请求
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private ArticleService articleService;
@RequestMapping("/reg")
public AjaxResult reg(Userinfo userinfo) {
// 非空效验和参数有效性效验
if (userinfo == null || !StringUtils.hasLength(userinfo.getUsername()) ||
!StringUtils.hasLength(userinfo.getPassword())) {
return AjaxResult.fail(-1, "非法参数");
}
// 密码加盐处理
userinfo.setPassword(PasswordUtils.encrypt(userinfo.getPassword()));
return AjaxResult.success(userService.reg(userinfo));
}
@RequestMapping("/login")
public AjaxResult login(HttpServletRequest request, String username, String password) {
// 1.非空效验
if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
return AjaxResult.fail(-1, "非法请求");
}
// 2.查询数据库
Userinfo userinfo = userService.getUserByName(username);
if (userinfo != null && userinfo.getId() > 0) { // 有效的用户
// 两个密码是否相同
if (PasswordUtils.check(password, userinfo.getPassword())) {
// 登录成功
// 将用户存储到 session
HttpSession session = request.getSession();
session.setAttribute(AppVariable.USER_SESSION_KEY, userinfo);
userinfo.setPassword(""); // 返回前端之前,隐藏敏感(密码)信息
return AjaxResult.success(userinfo);
}
}
return AjaxResult.success(0, null);
}
@RequestMapping("/showinfo")
public AjaxResult showInfo(HttpServletRequest request) {
UserinfoVO userinfoVO = new UserinfoVO();
// 1.得到当前登录用户(从 session 中获取)
Userinfo userinfo = UserSessionUtils.getUser(request);
if (userinfo == null) {
return AjaxResult.fail(-1, "非法请求");
}
// Spring 提供的深克隆方法
BeanUtils.copyProperties(userinfo, userinfoVO);
// 2.得到用户发表文章的总数
userinfoVO.setArtCount(articleService.getArtCountByUid(userinfo.getId()));
return AjaxResult.success(userinfoVO);
}
/**
* 注销(退出登录)
*
* @param session
* @return
*/
@RequestMapping("/logout")
public AjaxResult logout(HttpSession session) {
session.removeAttribute(AppVariable.USER_SESSION_KEY);
return AjaxResult.success(1);
}
/**
* 根据ID查询用户
*
*
*/
@RequestMapping("/getuserbyid")
public AjaxResult getUserById(Integer id) {
if (id == null || id <= 0) {
// 无效参数
return AjaxResult.fail(-1, "非法参数");
}
Userinfo userinfo = userService.getUserById(id);
if (userinfo == null || userinfo.getId() <= 0) {
// 无效参数
return AjaxResult.fail(-1, "非法参数");
}
// 去除 userinfo 中的敏感数据,ex:密码
userinfo.setPassword("");
UserinfoVO userinfoVO = new UserinfoVO();
BeanUtils.copyProperties(userinfo, userinfoVO);
// 查询当前用户发表的文章数
userinfoVO.setArtCount(articleService.getArtCountByUid(id));
return AjaxResult.success(userinfoVO);
}
}
2.ArticleController类
负责处理文章相关的HTTP请求
@RestController
@RequestMapping("/art")
public class ArticleController {
@Autowired
private ArticleService articleService;
/**
* 获取当前用户的文章列表
* */
@RequestMapping("/mylist")
public AjaxResult getMyList(HttpServletRequest request) {
//从 Session 中获取当前用户信息
Userinfo userinfo = UserSessionUtils.getUser(request);
//校验用户是否登录
if (userinfo == null) {
return AjaxResult.fail(-1, "非法请求");
}
//调用 Service层方法查询文章列表
List<Articleinfo> list = articleService.getMyList(userinfo.getId());
//返回响应数据
return AjaxResult.success(list);
}
/**
* 删除文章
* */
@RequestMapping("/del")
public AjaxResult del(HttpServletRequest request, Integer id) {
//参数校验:检查id是否合法(非空且大于 0)
if (id == null || id <= 0) {
return AjaxResult.fail(-1, "参数异常");
}
//从session中获取当前用户信息
Userinfo user = UserSessionUtils.getUser(request);
//检验用户是否登录
if (user == null) {
return AjaxResult.fail(-2, "用户未登录");
}
//调用service层方法删除文章
return AjaxResult.success(articleService.del(id, user.getId()));
}
/**
* 获取文章详情
* */
@RequestMapping("/detail")
public AjaxResult getDetail(Integer id) {
//检验文章id
if (id == null || id <= 0) {
return AjaxResult.fail(-1, "非法参数");
}
//调用service层方法获取文章详情
//将结果封装到AjaxResult中返回 成功的响应数据
return AjaxResult.success(articleService.getDetail(id));
}
/**
* 增加文章阅读量
* */
@RequestMapping("/incr-rcount")
public AjaxResult incrRCount(Integer id) {
if (id != null && id > 0) {
return AjaxResult.success(articleService.incrRCount(id));
}
return AjaxResult.fail(-1, "未知错误");
}
/**
* 增加文章
* */
@RequestMapping("/add")
public AjaxResult add(HttpServletRequest request, Articleinfo articleinfo) {
// 参数校验:articleinfo对象不能为空,title字段,content字段不能为空或仅含空格
if (articleinfo == null || !StringUtils.hasLength(articleinfo.getTitle()) ||
!StringUtils.hasLength(articleinfo.getContent())) {
// 返回失败响应
return AjaxResult.fail(-1, "非法参数");
}
//从session中获取当前用户信息
Userinfo userinfo = UserSessionUtils.getUser(request);
//检验用户是否登录:用户必须存在且id合法
if (userinfo == null || userinfo.getId() <= 0) {
return AjaxResult.fail(-2, "无效的登录用户");
}
// 将当前用户 ID(userinfo.getId())设置到文章对象中
// 确保文章与用户关联
articleinfo.setUid(userinfo.getId());
// 调用 Service 层方法保存文章,将结果封装到AjaxResult中 并返回成功的响应结果
return AjaxResult.success(articleService.add(articleinfo));
}
/**
* 更新文章
* */
@RequestMapping("/update")
public AjaxResult update(HttpServletRequest request, Articleinfo articleinfo) {
//参数校验
if (articleinfo == null || !StringUtils.hasLength(articleinfo.getTitle()) ||
!StringUtils.hasLength(articleinfo.getContent()) ||
articleinfo.getId() == null) {
return AjaxResult.fail(-1, "非法参数");
}
// 从session中获取当前用户信息
Userinfo userinfo = UserSessionUtils.getUser(request);
//
if (userinfo == null && userinfo.getId() == null) {
return AjaxResult.fail(-2, "无效用户");
}
//设置文章的uid为当前登录用户 ID(确保文章归属于正确用户)
//设置文章的updatetime为当前时间(记录更新时间)
articleinfo.setUid(userinfo.getId());
articleinfo.setUpdatetime(LocalDateTime.now());
return AjaxResult.success(articleService.update(articleinfo));
}
/**
* 查询列表根据分页
*
* @param pindex 当前页码(从1开始)
* @param psize 每页显示条数
* @return
*/
@RequestMapping("/listbypage")
public AjaxResult getListByPage(Integer pindex, Integer psize) {
// 1.参数校正
if (pindex == null || pindex <= 1) {
pindex = 1;
}
if (psize == null || psize <= 1) {
psize = 2;
}
// 分页公式的值 = (当前页码-1)*每页显示条数
int offset = (pindex - 1) * psize;
// 文章列表数据
List<Articleinfo> list = articleService.getListByPage(psize, offset);
// 当前列表总共有多少页
// a.总共有多少条数据
int totalCount = articleService.getCount();
// b.总条数/psize(每页显示条数)
double pcountdb = totalCount / (psize * 1.0);
// c.使用进一法得到总页数
int pcount = (int) Math.ceil(pcountdb);
HashMap<String, Object> result = new HashMap<>();
result.put("list", list);
result.put("pcount", pcount);
return AjaxResult.success(result);
}
}
(六)配置类——config包
拦截器
是spirng mvc中的核心组件之一
@Configuration
:声明这是一个配置类
@Configuration
public class AppConfig implements WebMvcConfigurer {
//拦截器注册方法
@Override
//InterceptorRegistry:Spring 提供的拦截器注册器,用于注册拦截器并配置拦截规则
public void addInterceptors(InterceptorRegistry registry) {
//. 添加登录拦截器
registry.addInterceptor(new LoginInterceptor())
//配置拦截路径
.addPathPatterns("/**")
.excludePathPatterns("/css/**")
.excludePathPatterns("/editor.md/**")
.excludePathPatterns("/img/**")
.excludePathPatterns("/js/**")
.excludePathPatterns("/login.html")
.excludePathPatterns("/reg.html")
.excludePathPatterns("/blog_list.html")
.excludePathPatterns("/blog_content.html")
.excludePathPatterns("/art/detail")
.excludePathPatterns("/art/incr-rcount")
.excludePathPatterns("/user/getuserbyid")
.excludePathPatterns("/art/listbypage")
.excludePathPatterns("/user/login")
.excludePathPatterns("/user/reg");
}
}
/**
* 登录拦截器,实现HandlerInterceptor接口
*/
public class LoginInterceptor implements HandlerInterceptor {
/**
* true -> 用户已登录
* false -> 用户未登录
*.
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取Session对象
HttpSession session = request.getSession(false);
//检验登录状态:Session存在,Session中存在用户信息
if (session != null && session.getAttribute(AppVariable.USER_SESSION_KEY) != null) {
// 登录成功时,将用户信息存入 Session:
System.out.println("当前登录用户为:" +
((Userinfo) session.getAttribute(AppVariable.USER_SESSION_KEY)).getUsername());
return true;
}
// 未登录:重定向到登录页面
response.sendRedirect("/login.html");
return false;
}
}
全局响应增强器
用于:统一 API 接口的返回(响应)格式,确保所有 Controller 方法的返回值都符合预定义的结构
/**
* 实现统一数据返回的保底类
* 说明:在返回数据之前,检测数据的类型是否为统一的对象,如果不是,封装成统一的对象
*/
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@Autowired
private ObjectMapper objectMapper;
/**
* 开关,如果是true才会调用beforeBodyWrite
*/
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
/**
* 对数据格式进行效验和封装
*/
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
1. 如果已经是AjaxResult类型,直接返回
if (body instanceof AjaxResult) return body;
/// 2. 处理String类型(特殊情况)
if (body instanceof String) {
return objectMapper.writeValueAsString(AjaxResult.success(body));
}
//3. 其他类型统一包装
return AjaxResult.success(body);
}
}