spring-boot 整合 JWT+SpringSecurity 进行登录认证

简要

1、SpringSecurity简要

  • 认证 (你是谁)
  • 授权 (你能干什么)
  • 攻击防护 (防止伪造身份)
    其核心就是一组过滤器链,项目启动后将会自动配置。最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在spring security中一种过滤器处理一种认证方式。

2、JWT 简要

  • JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

  • JSON Web Token由三部分组成,它们之间用圆点(.)连接
    第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

3、本文代码执行流程图大致如下

画图有点费时间。画的不好,见谅,主要为代码执行流程
spring-boot 整合 JWT+SpringSecurity 进行登录认证_第1张图片

登录

spring-boot 整合 JWT+SpringSecurity 进行登录认证_第2张图片

认证

spring-boot 整合 JWT+SpringSecurity 进行登录认证_第3张图片

4、pom.xml

加入必备依赖

 
        
            org.springframework.boot
            spring-boot-starter-security
        
        
        
        
            io.jsonwebtoken
            jjwt
            0.9.1
        
        
            com.alibaba
            fastjson
            1.2.61
        

一、配置SpringSecurity

类结构
spring-boot 整合 JWT+SpringSecurity 进行登录认证_第4张图片

1、SecurityUser

这里继承了UserAdmin (原用户类所有属性)和 UserDetails 权限判断属性( Security框架)

package com.ws.ldy.config.springSecurity.entity;

import com.ws.ldy.admin.model.entity.UserAdmin;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

/**
 * SecurityUser 权限判断类 (用户信息子类)
 */
@Data
public class SecurityUser extends UserAdmin implements UserDetails {

    private static final long serialVersionUID = 1L;


    //账户是否未过期,过期无法验证,在springSecurity 验证中自动调用
    boolean isAccountNonExpired;

    //指定用户是否解锁,锁定的用户无法进行身份验证,在springSecurity 验证中自动调用
    boolean isAccountNonLocked;

    //指示是否已过期的用户的凭据(密码),过期的凭据防止认证,在springSecurity 验证中自动调用
    boolean isCredentialsNonExpired;

    //是否可用 ,禁用的用户不能身份验证,在springSecurity 验证中自动调用
    boolean isEnabled;

    //登录用户名
    private String username;

    //登录密码
    private String password;

    //权限列表
    private Collection authorities;
}

2、XiJiaUserDetailsServiceImpl

继承 UserDetailsService ,登录认证方法,由SecurityConfig 来配置指定此类来认证

package com.ws.ldy.config.springSecurity.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ws.ldy.admin.mapper.AuthorityAdminMapper;
import com.ws.ldy.admin.mapper.UserAdminMapper;
import com.ws.ldy.admin.model.entity.AuthorityAdmin;
import com.ws.ldy.admin.model.entity.UserAdmin;
import com.ws.ldy.config.springSecurity.entity.SecurityUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * TODO 登录逻辑
 */
@Component
public class XiJiaUserDetailsServiceImpl implements UserDetailsService {

    // 用户表
    @Autowired
    private UserAdminMapper userAdminMapper;

    // 权限表
    @Autowired
    private AuthorityAdminMapper authorityAdminMapper;

    // 登录
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 账号查询( 账号必须唯一)
        UserAdmin userAdmin = userAdminMapper.selectOne(new LambdaQueryWrapper().eq(UserAdmin::getUsername, username));
        if (userAdmin == null) {
            return null;
        }

        // 账号密码及禁用过期等, // 状态 false, springSecurity 将验证失败,并返回不同的异常,失败方法根据不同异常返回不同的提示信息
        SecurityUser userDetail = userAdmin.convert(SecurityUser.class);
        userDetail.setUsername(userAdmin.getUsername());
        userDetail.setPassword(userAdmin.getPassword());
        userDetail.setAccountNonExpired(true);       // 是否过期
        userDetail.setAccountNonLocked(true);        // 是否解锁
        userDetail.setCredentialsNonExpired(true);   // 凭据(密码)是否过期
        userDetail.setEnabled(true);                 // 是否禁用

        // 查询权限并添加权限到userDetail
        List userIdRoleAuthority = authorityAdminMapper.findUserIdRoleAuthority(userAdmin.getId());
        List authorities = new ArrayList<>();
        for (AuthorityAdmin authority : userIdRoleAuthority) {
            authorities.add(new SimpleGrantedAuthority(authority.getUrl()));
        }
        userDetail.setAuthorities(authorities);
        return userDetail;
    }
}

3、SecurityConfig 配置类

package com.ws.ldy.config.springSecurity.config;

import com.ws.ldy.admin.mapper.AuthorityAdminMapper;
import com.ws.ldy.admin.model.entity.AuthorityAdmin;
import com.ws.ldy.config.jwt.filter.JWTLoginFilter;
import com.ws.ldy.config.jwt.filter.JWTValidFilter;
import com.ws.ldy.config.springSecurity.service.impl.XiJiaUserDetailsServiceImpl;
import com.ws.ldy.common.utils.auth.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.servlet.HandlerExceptionResolver;

import java.util.List;

/**
 * TODO  TODO Security配置文件,项目启动时就加载了
 *
 * @date 2020/7/5 0005 20:44
 * @return
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // 登录-认证方法->loadUserByUsername
    @Autowired
    private XiJiaUserDetailsServiceImpl xiJiaUserDetailsService;


    // 异常处理类,在 filter无法使用全局异常,在 .addFilter(new JWTValidFilter 中传递该对象过去,便于返回异常信息
    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    // 当前系统权限表
    @Autowired
    private AuthorityAdminMapper authorityAdminMapper;


    /**
     * 认证
     *
     * @return
     */
    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        //对默认的UserDetailsService进行覆盖
        authenticationProvider.setUserDetailsService(xiJiaUserDetailsService);
        authenticationProvider.setPasswordEncoder(new PasswordEncoder() {

            // 对密码MD5
            @Override
            public String encode(CharSequence rawPassword) {
                return MD5Util.encode((String) rawPassword);
            }

            // 判断密码是否正确, rawPassword 用户输入的密码,  encodedPassword 数据库DB的密码,当 XiJiaUserDetailsServiceImpl的loadUserByUsername方法执行完后执行
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                //String rawPass = MD5Util.encode((String) rawPassword);
                boolean result = rawPassword.equals(encodedPassword);
                return result;
            }
        });
        return authenticationProvider;
    }


    /**
     * TODO 授权
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // 只拦截需要拦截的所有接口, 拦截数据库权限表中的所有接口
        List authoritys = authorityAdminMapper.selectList(null);
        ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry eiur = http.authorizeRequests();
        authoritys.forEach((auth) -> {
            eiur.antMatchers(auth.getUrl()).hasAnyAuthority(auth.getUrl());
        });
        // 配置token验证及登录认证,过滤器
        eiur
                // 登录接口不需要权限控制,可删除,目前该接口不在权限列表中
                .antMatchers("/auth/login", "POST").permitAll()
                // 设置JWT过滤器
                .and()
                .addFilter(new JWTValidFilter(authenticationManager(), resolver))
                .addFilter(new JWTLoginFilter(authenticationManager(), resolver)).csrf().disable()
                // 剔除session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 开启跨域访问
        http.cors().disable();
        // 开启模拟请求,比如API POST测试工具的测试,不开启时,API POST为报403错误
        http.csrf().disable();
        // iframe 跳转错误处理 Refused to display 'url' in a frame because it set 'X-Frame-Options' to 'deny'
        http.headers().frameOptions().disable();
    }


    /**
     * There is no PasswordEncoder mapped for the id "null"
     * 原因:升级为Security5.0以上密码支持多中加密方式,恢复以前模式
     *
     * @return
     */
    @Bean
    public static NoOpPasswordEncoder passwordEncoder() {
        return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
    }
}

二、JWT 配置

1、登录 filter

package com.ws.ldy.config.jwt.filter;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ws.ldy.config.error.ErrorException;
import com.ws.ldy.common.utils.auth.JwtUtil;
import com.ws.ldy.config.springSecurity.entity.SecurityUser;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/***
 * TODO  登录  ===> POST请求( 账号:username=?, 密码:password=?)
 *
 * 登录会调用springSecurity的登录方法进行验证
 *

* ===== 登录成功 * http状态status状态返回200,并且自定义响应状态code返回200,响应头存放token,key = token,value = jwt生成的token内容 * ===== 登录失败 * http状态status状态返回401,并且自定义响应状态code返回401,并提示对应的内容 * ===== 权限不足 * http状态status状态返回403,并且自定义响应状态code返回403,并提示对应的内容 *

* @author 王松 * @mail [email protected] * @date 2020/7/5 0005 17:29 */ public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter { /** * 获取授权管理, 创建JWTLoginFilter时获取 */ private AuthenticationManager authenticationManager; /** * 异常处理类 */ private HandlerExceptionResolver resolver; /** * 创建JWTLoginFilter,构造器,定义后端登陆接口-【/auth/login】,当调用该接口直接执行 attemptAuthentication 方法 * * @param authenticationManager */ public JWTLoginFilter(AuthenticationManager authenticationManager, HandlerExceptionResolver resolver) { this.authenticationManager = authenticationManager; this.resolver = resolver; super.setFilterProcessesUrl("/auth/login"); } /** * TODO 一旦调用登录接口 /auth/login,立即执行该方法 * * @param request * @param response * @return * @throws AuthenticationException */ @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) { SecurityUser user = null; try { user = new ObjectMapper().readValue(request.getInputStream(), SecurityUser.class); } catch (IOException e) { // e.printStackTrace(); resolver.resolveException(request, response, null, new ErrorException(401, "没有传递对应的参数")); return null; } // 调用springSecurity的 XiJiaUserDetailsServiceImpl 的 loadUserByUsername 方法进行登录认证,传递账号密码 return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>())); } /** * TODO 一旦调用 springSecurity认证登录成功,立即执行该方法 * * @param request * @param response * @param chain * @param authResult * @throws IOException * @throws ServletException */ @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException { // 生成jwt 放入 Header SecurityUser userEntity = (SecurityUser) authResult.getPrincipal(); String jwtToken = JwtUtil.generateToken(userEntity); response.addHeader("token", jwtToken); // 响应 response.setContentType("application/json;charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); PrintWriter out = response.getWriter(); Map map = new HashMap(); map.put("code", 200); map.put("message", "登录成功!"); out.write(JSON.toJSONString(map)); out.flush(); out.close(); } /** * TODO 一旦调用 springSecurity认证失败 ,立即执行该方法 * * @param request * @param response * @param ex * @throws IOException * @throws ServletException */ protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) { if (ex instanceof UsernameNotFoundException || ex instanceof BadCredentialsException) { resolver.resolveException(request, response, null, new ErrorException(401, "用户名或密码错误")); } else if (ex instanceof InternalAuthenticationServiceException) { resolver.resolveException(request, response, null, new ErrorException(401, "没有账号信息")); } else if (ex instanceof DisabledException) { resolver.resolveException(request, response, null, new ErrorException(401, "账户被禁用")); } else { resolver.resolveException(request, response, null, new ErrorException(401, "登录失败!")); } } }

2、认证 filter

package com.ws.ldy.config.jwt.filter;

import com.ws.ldy.config.error.ErrorException;
import com.ws.ldy.common.utils.auth.JwtUtil;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;


/**
 * TODO jwt --> token 信息认证
 *
 * @author 王松
 * @mail [email protected]
 * @date 2020/7/5 0005 17:29
 */
@Slf4j
public class JWTValidFilter extends BasicAuthenticationFilter {

    // 异常处理类
    private HandlerExceptionResolver resolver;

    /**
     * SecurityConfig 配置中创建该类实例
     */
    public JWTValidFilter(AuthenticationManager authenticationManager, HandlerExceptionResolver resolver) {
        // 获取授权管理
        super(authenticationManager);
        // 获取异常处理类
        this.resolver = resolver;
        this.resolver = resolver;
    }


    /**
     * 拦截请求
     *
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("请求方式:{} 请求URL:{} ", request.getMethod(), request.getServletPath());
        // 获取token, 没有token直接放行
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token) || "null".equals(token)) {
            super.doFilterInternal(request, response, chain);
            return;
        }
        // 有token进行权限验证
        List userAuthList = null;
        String username = null;
        try {
            //  权限列表
            userAuthList = JwtUtil.getUserAuth(token);
            //  获取账号
            username = JwtUtil.getUsername(token);
        } catch (SignatureException ex) {
            resolver.resolveException(request, response, null, new ErrorException(10000, "JWT签名与本地计算签名不匹配"));
            return;
        } catch (ExpiredJwtException ex) {
            resolver.resolveException(request, response, null, new ErrorException(10000, "登录过期"));
            return;
        } catch (Exception e) {
            resolver.resolveException(request, response, null, new ErrorException(10000, "JWT解析错误"));
            return;
        }
        //  添加账户的权限信息,和账号是否为空,然后保存到Security的Authentication授权管理器中
        if (StringUtils.isNotBlank(username) && userAuthList != null) {
            SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(username, null, userAuthList));
        }
        super.doFilterInternal(request, response, chain);
    }
}

3、JWT生成工具类

package com.ws.ldy.common.utils.auth;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.ws.ldy.config.springSecurity.entity.SecurityUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.util.Date;
import java.util.List;

/***
 * TODO  jwt 工具类
 * @author 王松
 * @mail [email protected]
 * @date 2020/7/5 0005 19:13
 */
public class JwtUtil {

    // 主题
    private static final String SUBJECT = "xijia";

    // jwt的token有效期,
    //private static final long EXPIRITION = 1000L * 60 * 60 * 24 * 7;//7天
    private static final long EXPIRITION = 1000L * 60 * 30;   // 半小时

    // 加密key(黑客没有该值无法篡改token内容)
    private static final String APPSECRET_KEY = "xijia";

    // 用户url权限列表key
    private static final String AUTH_CLAIMS = "auth";

    /**
     * TODO  生成token
     *
     * @param user
     * @return java.lang.String
     * @date 2020/7/6 0006 9:26
     */
    public static String generateToken(SecurityUser user) {
        String token = Jwts
                .builder()
                // 主题
                .setSubject(SUBJECT)
                // 添加jwt自定义值
                .claim(AUTH_CLAIMS, user.getAuthorities())
                .claim("username", user.getUsername())
                .claim("userId", user.getId())
                .claim("head", user.getHead())
                .setIssuedAt(new Date())
                // 过期时间
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRITION))
                // 加密方式,加密key
                .signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();
        return token;
    }


//    public static Claims checkJWT(String token) {
//        try {
//            final Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
//            return claims;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return null;
//        }
//    }

    /**
     * 获取用户Id
     *
     * @param token
     * @return
     */
    public static String getUserId(String token) {
        Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
        return claims.get("userId").toString();
    }


    /**
     * 获取用户名
     *
     * @param token
     * @return
     */
    public static String getUsername(String token) {
        Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
        return claims.get("username").toString();
    }

    /**
     * 获取用户角色的权限列表, 没有返回空
     *
     * @param token
     * @return
     */
    public static List getUserAuth(String token) {
        Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
        List auths = (List) claims.get(AUTH_CLAIMS);
        String json = JSONArray.toJSONString(auths);
        List grantedAuthorityList = JSON.parseArray(json, SimpleGrantedAuthority.class);
        return grantedAuthorityList;
    }

    /**
     * 是否过期
     *
     * @param token
     * @return
     */
    public static boolean isExpiration(String token) {
        Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
        System.out.println("过期时间: " + claims.getExpiration());
        return claims.getExpiration().before(new Date());
    }
}

三、系统错误配置

1、WebServerAutoConfiguration (系统异常转发)

package com.ws.ldy.config.error;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

@Configuration
public class WebServerAutoConfiguration {
    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400");
        ErrorPage errorPage401 = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401");
        ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN, "/error/403");
        ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");
        ErrorPage errorPage415 = new ErrorPage(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "/error/415");
        ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");
        factory.addErrorPages(errorPage400, errorPage401, errorPage403, errorPage404, errorPage415, errorPage500);
        return factory;
    }
}

2、ErrorController (返回前端错误信息)

我这里抛的自定义异常走全局异常类,可以自己修改一下

package com.ws.ldy.config.error;

import com.ws.ldy.base.controller.BaseController;
import com.ws.ldy.common.result.EnumUtils;
import com.ws.ldy.common.result.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * TODO  WebServerAutoConfiguration 转发异常转发过来的信息,返回 json参数
 *
 * @author 王松
 * @mail [email protected]
 * @date 2019/11/19 9:43
 * 方式1、直接跳转到具体错误页面
 * 方式2、返回json格式数据,由前端处理
 */
@SuppressWarnings("all")
@Controller
@Slf4j
public class ErrorController extends BaseController {

    /**
     * TODO  方式2:系统错误返回json
     *
     * @param code 对应错误码,ErrorPageConfig配置
     * @return java.util.Map
     * @date 2019/11/18 21:14
     */
    @RequestMapping(value = "/error/{code}")
    @ResponseBody
    public void error(@PathVariable int code) {
        // 根据状态值查询对应的枚举
        ResultEnum errorConstantEnum = EnumUtils.getByCode(Integer.valueOf(code), ResultEnum.class);
        // 返回对应提示
        if (errorConstantEnum != null) {
            throw new ErrorException(errorConstantEnum);
        }
        //返回500错误
        throw new ErrorException(ResultEnum.SYS_ERROR_CODE_500);
    }
}

本文到此结束,如果觉得有用,动动小手点赞或关注一下呗,将不定时持续更新更多的内容…,感谢大家的观看!

你可能感兴趣的:(springboot)