JAVA后端开发注意事项
JAVA后端开发注意事项
一.
>登录功能
@Slf4j
@RestController
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp){
log.info("登录功能{}",emp);
Emp e = empService.login(emp);
return e!=null ?Result.success():Result.error("用户名或密码错误");
}
}
Emp login(Emp emp);
@Override
public Emp login(Emp emp) {
return empMapper.getByUsernameAndPassword(emp);
}
@Select("select * from emp where username = #{username} and password=#{password} ")
Emp getByUsernameAndPassword(Emp emp);
二.登录校验
没有登录校验会导致没有验证直接操作页面,不安全。
统一拦截技术 过滤器Filter 拦截器Interceptor
登录标记,每次成功登录都能获取此标记。
会话技术,浏览器与服务器的连接,几个浏览器就有几个会话,一个会话有多个操作
会话跟踪:一种维护浏览器状态的方法,服务器识别多次请求是否是同一浏览器,所以在同一次会话中多次请求的时候共享数据。
客户端会话跟踪技术 cookie
优点:HTTP支持的技术,name自动请求Cookie,自动响应set-Cookie
缺点:移动端无法使用,不安全,用户可以禁用,cookie不能跨域。跨域区分13个维度:协议,IP/域名,端口
服务器会话跟踪技术 session
优点:存储在服务端,安全
缺点:服务器集群环境下无法直接使用Session(负载均衡情况下)
cookie的缺点。
负载均衡:负载均衡服务器根据子服务器情况发送操作指令。
package com.itheima.controller;
import com.itheima.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
-
HttpSession演示
*/
@Slf4j
@RestController
public class SessionController {//设置Cookie
@GetMapping(“/c1”)
public Result cookie1(HttpServletResponse response){
response.addCookie(new Cookie(“login_username”,“itheima”)); //设置Cookie/响应Cookie
return Result.success();
}//获取Cookie
@GetMapping(“/c2”)
public Result cookie2(HttpServletRequest request){
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if(cookie.getName().equals(“login_username”)){
System.out.println("login_username: "+cookie.getValue()); //输出name为login_username的cookie
}
}
return Result.success();
}@GetMapping(“/s1”)
public Result session1(HttpSession session){
log.info(“HttpSession-s1: {}”, session.hashCode());session.setAttribute("loginUser", "tom"); //往session中存储数据 return Result.success();
}
@GetMapping(“/s2”)
public Result session2(HttpServletRequest request){
HttpSession session = request.getSession();
log.info(“HttpSession-s2: {}”, session.hashCode());Object loginUser = session.getAttribute("loginUser"); //从session中获取数据 log.info("loginUser: {}", loginUser); return Result.success(loginUser);
}
}
令牌技术
优点:支持PC端,移动端
解决集群环境下的认证问题
减轻服务器端存储压力。
缺点:需要自己实现
JWT令牌
JSON Web Token(https://jwt.io/)
定义了一种简洁的,自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
组成部分3:
第一部分:Header(头),记录令牌类型,签名算法,{“alg”:“HS356”,“type”:“JWT”} “alg”算法,"type"令牌类型
第二部分:Payload(有效载荷),携带一些自定义信息,默认信息等。例如{“id”:1,“username”:“Tom”}
第三部分:Signature(签名),防止Token被篡改,确保安全性。将header,payload,加入指定密钥,指定的签名算法计算得到。
第1,2部分通过Base64编码得到JWT令牌中的格式,
Base64:是一种基于64个可打印字符(A-Z a-z 0-9 +/)表示二进制数据的编码方式。
登录自动生成令牌并且下发到网页端
public Result login(@RequestBody Emp emp){
log.info(“登录功能{}”,emp);
Emp e = empService.login(emp);
//生成令牌,并且下发到网页端
if(e!=null){
Map<String, Object> claim = new HashMap<>();
claim.put("id",e.getId());
claim.put("username",e.getUsername());
claim.put("password",e.getPassword());
String JwtLogin = JwtUtils.generateJwt(claim);
return Result.success(JwtLogin);
}
return Result.error("用户名或密码错误");
}
过滤器(Filter)
概念:Filter过滤器,是JavaWeb三大组件(Servlet,Filter,Listener)之一
过滤器将对资源的请求拦截下,以此实现登录校验,统一编码处理,敏感字符处理等
Filter快速入门
1.定义Filter: 定义一个类,实现Filter接口,并重写其所有方法
2.配置Filter: Filter类上加@WebFilter注解,配置拦截资源的路径。引导类上加
@ServletComponentScan开启Servlet组件支持
过滤器链
介绍:一个web应用中,配置多个过滤器,多个过滤器形成过滤器链。
顺序:注解配置的Filter,优先级按照过滤器类名(字符串)的自然排序。
登录校验
@Slf4j
@WebFilter
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req=(HttpServletRequest) servletRequest;
HttpServletResponse rep = (HttpServletResponse) servletResponse;
//1 获取请求url
String url =req.getRequestURI().toString();
log.info(“获取请求url”,url);
//2.判断是否登录,url中有没有login
if(url.contains(“login”)){
log.info(“登录操作,放行”);
filterChain.doFilter(servletRequest,servletResponse);
return;
}
//3.从请求req中获取请求头tooken
String jj =req.getHeader("token");
//4.判断JWT令牌是否存在
if(!StringUtils.hasLength(jj)){
log.info("令牌不存在");
//返回错误提示信息
Result error= Result.error("NOT_LOGIN");
//返回JSON格式
String s_json= JSON.toJSONString(error);
rep.getWriter().write(s_json);
return;
}
//5.令牌校验
try {
JwtUtils.parseJWT(jj);
}catch (Exception e){
e.printStackTrace();
log.info("令牌解析失败");
Result error= Result.error("NOT_LOGIN");
//返回JSON格式
String s_json= JSON.toJSONString(error);
rep.getWriter().write(s_json);
return;
}
//6.放行
log.info("令牌合法,放行");
filterChain.doFilter(servletRequest,servletResponse);
}
}
拦截器Interceptor
概念,一种动态拦截方法调用的机制,Spring框架中提供的,用来动态拦截控制器方法的执行
作用:拦截请求,指定方法调用前后,根据业务执行预先设定的代码。
根据需求配置不同的拦截路径
/* 一级路径
/** 任意级路径
/depts/* /depts下一级路径
/depts/** /depts下任意级路径
拦截器的执行流程
浏览器的请求-》《-Filter过滤器-》《-DispatcherServiet服务器-》《-Interceptor拦截器-》《-controller控制器
。
过滤器和拦截器
接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口
拦截范围不同:过滤器Filter会拦截所有资源,Interceptor只会拦截Spring环境中的资源。
拦截器新建Interceptor类
@Slf4j
@Component
public class InterCheckInterceptor implements HandlerInterceptor {
@Override
//目标方法放行前运行,true放行,false不放行
public boolean preHandle(HttpServletRequest req, HttpServletResponse rep, Object handler) throws Exception {
//登录校验工作,在操作前
//1 获取请求url
String url =req.getRequestURI().toString();
log.info("获取请求url",url);
//2.判断是否登录,url中有没有login
if(url.contains("login")){
log.info("登录操作,放行");
return true;
}
//3.从请求req中获取请求头tooken
String jj =req.getHeader("token");
//4.判断JWT令牌是否存在
if(!StringUtils.hasLength(jj)){
log.info("令牌不存在");
//返回错误提示信息
Result error= Result.error("NOT_LOGIN");
//返回JSON格式
String s_json= JSON.toJSONString(error);
rep.getWriter().write(s_json);
return false;
}
//5.令牌校验
try {
JwtUtils.parseJWT(jj);
}catch (Exception e){
e.printStackTrace();
log.info("令牌解析失败");
Result error= Result.error("NOT_LOGIN");
//返回JSON格式
String s_json= JSON.toJSONString(error);
rep.getWriter().write(s_json);
return false;
}
//6.放行
log.info("令牌合法,放行");
System.out.println("preHandle----");
return true;
}
@Override //目标方法运行后放行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle-----------");
}
@Override //视图渲染后放行,最后运行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion -----------");
}
}
新建WebConfig类
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private InterCheckInterceptor interCheckInterceptor;
@Override
// public void addInter
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interCheckInterceptor).addPathPatterns(“/**”).excludePathPatterns(“/login”);
}
}
三.异常处理
出现异常处理方法
1.在Controller的方法中进行try…catch处理,代码臃肿
2.全局异常处理器,推荐
//全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class) //捕获所有异常
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("对不起,操作异常,请联系管理员");
}
}