JAVA项目实战瑞吉外卖—day1

技术选型

技术概览

数据库环境搭建

数据库表

导入前端页面资源

因为创建的是maven初始化项目,没有自带的springboot文件目录,前端页面有些访问被禁止,静态资源的访问方法有两种

后端开发

创建SpringMVC静态资源页面访问拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* 设置静态资源映射
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始进行静态资源映射...");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
}

在resource目录下创建static目录

将静态资源文件放进去,因为springboot框架自动开放static资源访问

编写springboot通用模板

MVC三层架构

目录结构

编写通用返回类

返回一个通用结果类,服务端响应的所有结果最终都是包装成这种类型返回给前端页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Data
public class R<T> {

private Integer code; //编码:1成功,0和其它数字为失败

private String msg; //错误信息

private T data; //数据

private Map map = new HashMap(); //动态数据

public static <T> R<T> success(T object) {
R<T> r = new R<T>();
r.data = object;
r.code = 1;
return r;
}

public static <T> R<T> error(String msg) {
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}

public R<T> add(String key, Object value) {
this.map.put(key, value);
return this;
}

}

登录接口编写

个人认为将业务方法写在service层中更好,controller注解调用更为简便

写完项目会进行优化——–TODO

使用MD5加密方式校验密码

数据库中不能存在明文密码在,使用MD5加密,最好添加盐值混淆密码

1
2
3
// 1.使用MD5加密方式将密码进行加密
String password = employee.getPassword();
password = DigestUtils.md5DigestAsHex(password.getBytes());
1
2
3
4
5
6
7
/**
* 盐值 混淆密码 加密
*/
private static final String salt = "passwordAc";
String password = employee.getPassword();
//2.对代码进行加密
String newPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());

这样在数据库中混淆密码进行安全保护

判断用户是否正常 能否进行登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 2.根据页面提交的员工名username查询数据库
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Employee::getUsername,employee.getUsername());
Employee emp = employeeService.getOne(queryWrapper);

// 3.如果没有该员工返回登陆失败结果
if (emp == null){
return R.error("用户不存在");
}

// 4.密码对比,如果密码不一致返回登陆失败结果
if (!emp.getPassword().equals(password)){
return R.error("密码错误");
}

// 5.员工状态,如果为禁用状态,则返回员工以禁用的结果
if (emp.getStatus() == 0){
return R.error("该员工以禁用");
}

// 6.登录成功,将员工的id存入session并返回登录成功结果
request.getSession().setAttribute("employee",emp.getId());

return R.success(emp);

登出接口编写

根据前端页面返回的请求是POST,所以编写接口也应该未POST

1.移除用户登录态

2.跳转到登录页面

1
2
3
4
5
6
7
8
9
10
11
 /**
* 登出 清除用户登录态
* 清除保存在session中的员工id
* @param request
* @return
*/
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request){
request.getSession().removeAttribute("employee");
return R.success("退出成功!");
}

完善登录接口

设置登录(SpringMVC)拦截器或者javaweb过滤器

这里使用的是过滤器记得在启动类入口添加@ServletComponentScan注解

1
2
3
4
5
6
7
8
9
@Slf4j
@SpringBootApplication
@ServletComponentScan
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class,args);
log.info("项目启动成功......");
}
}

未登录无法查看管理窗口页面,需要跳转到登录页面

后端过滤器

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
@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.获得本次请求的URI
String requestURI = request.getRequestURI();

//设置不需要登录即可访问的地址
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};

//2.检查本次请求是否需要放行
boolean check = check(urls, requestURI);

//3.如果不需要出来直接放行
if (check) {
filterChain.doFilter(request, response);
return;
}

//4.判断登录状态,如果已登录,则直接放行
if (request.getSession().getAttribute("employee")!=null){
filterChain.doFilter(request, response);
return;
}
//5.如果是未登录的状态则返回未登录的结果,通过输出流的方式向客户端页面响应数据
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;

}

/**
* 路径匹配,是否需要放行
*
* @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;
}
}

这里通过后端进行页面路径访问判断,从而得出哪些路径需要进行拦截,在根据前端的拦截器实现拦截页面跳转到登录界面,根据前后端传输数据”NOTLOGIN”来响应页面跳转

前端拦截器

1
2
3
4
5
6
7
8
9
10
// 响应拦截器
service.interceptors.response.use(res => {
if (res.data.code === 0 && res.data.msg === 'NOTLOGIN') {// 返回登录页面
console.log('---/backend/page/login/login.html---')
localStorage.removeItem('userInfo')
window.top.location.href = '/backend/page/login/login.html'
} else {
return res.data
}
},

Question

这里的路径匹配器我理解不了

/**是允许访问目录及子目录下的所有文件,意思为放行,放行还怎么拦截

1
2
//路径比较资源类 路径匹配器
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();