登陆页面制作和共享优化

52 阅读4分钟

登陆页面

1 判断账号密码是否一致

1.1 添加jjwt依赖
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
1.2 编写JWTUtils工具类
public class JWTUtils {
    //匿名构造器
    private JWTUtils(){}

    public static String createJWTStr(Map<String,Object> map) {

        //利用JJWT api的builder方法生成令牌
        String jwtStr = Jwts.builder()
                //签名编码和签名,签名不能有中文, 否则超出界定范围
                .signWith(SignatureAlgorithm.HS256, "Donald Trump")
                //payload--有效载荷--自定义传参
                .addClaims(map)
                //设置有效期限. 1000*60*10 = 1000毫秒(1秒)*60(分钟/秒)*10 == 10分钟
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 10 ))
                // 编写 => 输出格式为String
                .compact();

        System.out.println(jwtStr);
        return jwtStr;
    }

    //解析JWT令牌
    public static void parseJWTStr(String str){
       Jwts.parser()
                // 签名
                .setSigningKey("Donald Trump")
                // 解析(令牌)
                .parse(str)
               //获得body
                .getBody();
    }
}
1.3 编写 Controller

@RestController
@Slf4j
public class LoginController {

    @Autowired
    private LoginService loginService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {
        Emp empReturn = loginService.login(emp);
		//返回值null代表登录失败
        if(empReturn == null){
            return Result.failed();
        }else {
        //登陆成功, 制造JWT令牌
            Map map = new HashMap<>();
            map.put("username",emp.getUsername());
            map.put("id",emp.getId());
            //用JWTUtils工具类生成JWT令牌
            String jwtStr = JWTUtils.createJWTStr(map);
            return Result.success(jwtStr);
        }
    }
}
1.4 编写Service (可以看成是用户的Service)
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private LoginMapper loginmapper;
    @Override
    public Emp login(Emp emp) {
        //mapp查找,成功返回Emp对象, 失败则不返回对象
        Emp empReturn = loginmapper.login(emp);
        return empReturn;
    }
}
1.5 编写Mapper (可以看成是用户的Mapper)
@Mapper
public interface LoginMapper {
    @Select("select * from emp where username = #{username} and password = #{password}")
    Emp login(Emp emp);
}
1.6 异常和报错
1.6.1 制作登陆token令牌时报错

​ 在制作登陆令牌时偶尔会出现 ERROR: .ClassNotFoundException 错误, 这是因为在 Java 9 及以上的版本中,javax.xml.bind.DatatypeConverter 类被标记为不推荐使用,并且从标准的 Java SE 库中移除。因此,在某些情况下,当代码依赖旧的库或框架时,可能会出现该异常。

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter] with root cause

image-20230916111841609转存失败,建议直接上传图片文件

​ 解决办法是手动添加jaxb-api依赖

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
1.6.2 解析token令牌时报错

​ 解析过程中发现parseJWT() 报错ERROR:

.IllegalArgumentException: A signing key must be specified if the specified JWT is digitally signed

​ 原因是生成token和解析token所设置的Signingkey不匹配导致.

​ 解决办法就是检查两次设置的signingkey是否匹配

2 Filter 过滤器

2.1 编写一个类实现Filter接口并重写其所有方法, 并在Filter类上加 @WebFilter 注解,配置拦截资源的路径
# 添加依赖fastjson
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.32</version>
</dependency>
//@WebFilter(urlPatterns ="/*")的作用是对所有 URL 请求进行拦截和处理。
@WebFilter(urlPatterns ="/*")
public class doFilter implements Filter {
    //初始化方法, 只调用一次
    @Override
    // FilterConfig 对象可以获取到 ServletContext 和其他配置参数
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }

    // ctrl+o 重写方法
    //拦截到请求之后调用, 调用多次
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Demo 拦截到了请求...放行前逻辑");
        //强制转换以便于获取请求
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 获取请求url URI 是一个用于标识资源的字符串
        String url = request.getRequestURI();
        System.out.println("拦截了:"+url);
        // 判断请求url是否包含login, 有则放行
        if(url.contains("login")){
            //filter的放行方法
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }
        // 获取请求头中token
        String token = request.getHeader("token");
        // 利用StringUtils工具类的方法判断token是否存在
        if(!StringUtils.hasLength(token)){
            Result r = Result.failed("NOT_LOGIN");
            //序列化为 JSON 格式的字符串
            String jsonStr = JSONObject.toJSONString(r);
            //写入响应中
            response.getWriter().write(jsonStr);
            return;
        }
        //解析token
        try{
            JWTUtils.parseJWTStr(token);
            // 解析成功,则放行
            filterChain.doFilter(servletRequest,servletResponse);
        }catch (Exception e){
            e.printStackTrace();
            Result r = Result.failed("NOT_LOGIN");
            String jsonStr = JSONObject.toJSONString(r);
            response.getWriter().write(jsonStr);
            return;
        }

        System.out.println("过滤执行了");
    }

    //销毁方法, 只调用一次
    @Override
    public void destroy() {
        System.out.println("destroy 销毁方法执行了");
    }
}
2.2 在引导类上加 @ServletComponentScan 开启Servlet组件
@ServletComponentScan
@SpringBootApplication
public class Day25TillasRe3Application {

    public static void main(String[] args) {
        SpringApplication.run(Day25TillasRe3Application.class, args);
    }

}

3 Interceptor 拦截器

3.1 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法。
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截呀");
        String url = request.getRequestURI();
        System.out.println("拦截了"+ url);
        //判断请求rul中是否包含login
        if(url.contains("login")){
            return true;
        }
        //获取请求token
        String token = request.getHeader("token");
        //判断令牌是否存在
        if(!StringUtils.hasLength(token)){
            Result r = Result.failed("NOT_LOGIN");
            //拼接json
            String string = JSONObject.toJSONString(r);
            response.getWriter().write(string);
            return false;
        }
        //解析
        try{
            JWTUtils.parseJWTStr(token);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            Result r = Result.failed("NOT_LOGIN");
            //拼接json
            String string = JSONObject.toJSONString(r);
            response.getWriter().write(string);
            return false;
        }
    }

    @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");
    }
}
3.2 生成一个Config文件夹 内有 Cofig配置文件, 在配置文件中注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    @Override
    //addInterceptors方法用于添加拦截器到拦截器注册表(InterceptorRegistry)
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
    }
}

4 Global Exception Handler 全局异常处理器

//@RestControllerAdvice捕获应用程序中抛出的所有类型的 Exception 异常,并进行统一处理。
//@RestControllerAdvice = @ResponseBody +@Controller Advice
@RestControllerAdvice
public class GlobalExceptionHandler {

    // @ExceptionHandler 注解标识的参数指定了要处理的异常类型为 Exception.class,
    // 表示捕获所有的异常。当应用程序中抛出异常时,会被这个方法捕获到
    @ExceptionHandler(Exception.class)
    public Result exception(Exception ex){
        // 打印堆栈信息
        ex.printStackTrace();
        return Result.failed("you are failed");
    }
}