目录
Day01
一.SpringBoot的配置文件application.yml
二.创建配置类WebMvcConfig,设置静态资源映射,否则无法访问页面
三.创建与前端交互的结果类R
4.后台登录功能实现中的注意事项
5.后台用户退出功能
6.用户登陆过滤器
server:
port: 8080
spring:
application:
name: reggie_take_out
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver #MP的相关配置
url: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
#user_name--->userName
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID #设置雪花算法
reggie:
path: D:\food\
在配置文件中开启实体和实体属性映射可以大大方便我们开发,
并且给Id填充设置雪花算法,在实体类中要进行设定
private static final long serialVersionUID = 1L;
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* 设置静态资源映射
* 对静态资源放行,不通过Mvc可以直接访问
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始进行静态资源映射");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
@Data
public class R {
private Integer code; //编码:1成功,0和其它数字为失败
private String msg; //错误信息
private T data; //数据
private Map map = new HashMap(); //动态数据
public static R success(T object) {
R r = new R();
r.data = object;
r.code = 1;
return r;
}
public static R error(String msg) {
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}
交互结果类是十分重要的他关系到我们与前端的信息交互,在开发过程中是要和前端人软具体协商好来进行具体编写,一般就包括成功和错误返回的提示信息标志Code,还有响应的数据data。
@Data注解是表示启用lombok插件,开启相当于写了Setter和Getter方法等
//1.将页面提交的password进行md5加密处理
String password = employee.getPassword();
password = DigestUtils.md5DigestAsHex(password.getBytes());
//2.根据页面提交的的用户名username查询数据库
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Employee::getUsername, employee.getUsername());
//通过上述方法来获取数据库中所有数据,不能使用getById因为提供的是userName
Employee emp = employeeService.getOne(queryWrapper);
数据库中存储的密码都是加密过的在进行登录校验之前要先从页面获取到的密码进行MD5加密处理不然在数据库中是查不到的,数据库中设置了userName字段唯一,进行登录判断时还要判断员工的状态status是否是禁用状态。
//6.登陆成功,将员工ID存入Session并返回登陆成功结果
request.getSession().setAttribute("employee", emp.getId());
return R.success(emp);
登录成功将员工的Id存入Session中,这很重要,在前端页面中会需要展示当前登录的用户Id,并且在之后做过滤器判断时Session中有没有Id数据也是关键。
@PostMapping("/logout")
public R logout(HttpServletRequest request) {
//清楚session中的数据
request.getSession().removeAttribute("employee");
return R.success("退出成功");
退出功能就是将登录功能传入的Session移除,并且前端返回到登录界面,原理是在过滤器中每次请求都会判断Session中是否有存用户登录的Id如果没有就会跳转到登陆界面。
/**
* 过滤器检查用户是否已经登录完成
*/
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {
//进行路径匹配
public static final AntPathMatcher PATH_MATCHER =new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1.获取本次请求路径
String requestURI = request.getRequestURI();
log.info("拦截到请求:{}",requestURI);
//1.定义不需要处理的路径
String[] urls =new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**",
"/common/**",
"/user/login",
"/user/sendMsg"
};
//2.判断本次请求是否需要处理
boolean check = check(urls, requestURI);
//3.如果不要处理直接放行
if (check){
log.info("本次请求{}不用处理",requestURI);
filterChain.doFilter(request,response);//放行
return;
}
//4.1判断是否登录,已经登录则放行
if (request.getSession().getAttribute("employee") != null){
Long empId = (Long) request.getSession().getAttribute("employee");
BaseContext.setCurrentId(empId);
filterChain.doFilter(request,response);//放行
return;
}
//4.2判断用户是否登录,已经登录则放行
if (request.getSession().getAttribute("user") != null){
Long userId = (Long) request.getSession().getAttribute("user");
BaseContext.setCurrentId(userId);
filterChain.doFilter(request,response);//放行
return;
}
log.info("用户未登录");
//5.如果未登录则返回未登录结果
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;
}
/**
* 路径匹配,判断本次请求是否需要放行
* 会判断本此请求要调用的所有资源如果有一个是不能访问的就返回false就不能访问到。
* @param urls
* @param requestURI
* @return
*/
public boolean check(String[] urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match(url,requestURI);
if (match){
return true;
}
}
return false;
}
}
首先我们要清楚那些资源是不用被过滤的,因为要展示前端页面,所以前端页面对应的资源是不用被过滤的,如果我们判定到用户没有登陆那么就要返回到登陆界面让用户登陆所以和登陆相关的界面也是不需要过滤的。
这里的路径匹配AntPathMatcher PATH_MATCHER是由Spring提供的方法。并且要在SpringBoot的启动类上加上@ServletComponentScan注解用于扫描我们编写的过滤器。
7.新增用户功能
/**
* 新增功能
*
* @param request
* @param employee
* @return
*/
@PostMapping
public R save(HttpServletRequest request, @RequestBody Employee employee) {
log.info(employee.toString());
//1.设置密码初始值
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
//获取当前登录用户的ID
Long empID = (Long) request.getSession().getAttribute("employee");
employee.setCreateUser(empID);
employee.setUpdateUser(empID);
try {
employeeService.save(employee);
} catch (Exception e) {
R.error("新增员工失败");
}
return R.success("添加成功");
}
新增员工这里统一设置了初始登陆密码为123456,并且对创建时间,创建人这些字段进行了赋值。注意的是在employee表中是设置了userName字段唯一的,如果在输入时输入的userName已经存在这时候是会报异常的针对这种异常进行了异常处理。具体异常大概就是 告诉你字段数据在表中已经存在。
全局异常处理器
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R exceptionHandler(SQLIntegrityConstraintViolationException ex) {
if (ex.getMessage().contains("Duplicate entry")) {
String[] split = ex.getMessage().split(" ");
return R.error(split[2] + "已存在");
}
return R.error("未知错误");
}
/**
* 自定义异常处理器
*
* @param ex
* @return
*/
@ExceptionHandler(CustomException.class)
public R exceptionHandler(CustomException ex) {
return R.error(ex.getMessage());
}
}
这里是根据返回的异常来进行判断,根据" "进行切割zhangsan在第三位对应的索引为2,然后我们就可以向前端返货账号已存在的错误。说得到这就把异常处理这里说完,这里还定义了业务异常处理。
/**
* 自定义业务异常类
*/
public class CustomException extends RuntimeException{
public CustomException(String message){
super(message);
}
}
先要创建出业务异常类,什么时候用呢,举一个例子
比如我们进行了菜品的分类,比如说在川菜这个类别下面有鱼香肉丝,宫保鸡丁顶。当我们要删除川菜这个分类时显然是不行的因为他还关联了菜品,这时我们就要返回给前端提示当前分类下还有菜品不能删除。