系统管理后端开发-02

UserService

package com.it6666.service;

import com.it6666.domain.User;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * @author BNTang
 */
public interface UserService {

    /**
     * 根据手机号查询用户
     *
     * @param phone 手机号
     * @return      根据手机号查询到的用户对象
     */
    User queryUserByPhone(String phone);

    /**
     * 根据用户ID查询用户
     *
     * @param userId 用户编号
     * @return       根据用户ID查询到的用户对象
     */
    User getOne(Long userId);
}

UserServiceImpl

package com.it6666.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.it6666.mapper.UserMapper;
import com.it6666.domain.User;
import com.it6666.service.UserService;

/**
 * @author BNTang
 */
@Service
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;

    public UserServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public User queryUserByPhone(String phone) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq(User.COL_PHONE, phone);
        return this.userMapper.selectOne(qw);
    }

    @Override
    public User getOne(Long userId) {
        return this.userMapper.selectById(userId);
    }
}

最终结构图

生成Menu菜单相关实体以及接口和持久层,注意选择生成到那个项目中, 前面生成过了User在生成Menu就很快了,基本上动的很少

修改MenuService

package com.it6666.service;

import com.it6666.domain.Menu;
import com.it6666.domain.SimpleUser;

import java.util.List;

/**
 * description: MenuService
 * date: 2020-09-03 21:39
 * author: 30315
 * version: 1.0
 */
public interface MenuService {

    /**
     * 查询菜单信息
     * 如查用户是超级管理员,那么查询所以菜单和权限
     * 如果用户是普通用户,那么根据用户ID关联角色和权限
     *
     * @param isAdmin    是否是超级管理员
     * @param simpleUser 如果 isAdmin=true, simpleUser可以为空
     */
    public List<Menu> selectMenuTree(boolean isAdmin, SimpleUser simpleUser);
}

修改MenuServiceImpl

package com.it6666.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.it6666.constants.Constants;
import com.it6666.domain.SimpleUser;
import org.springframework.stereotype.Service;

import java.util.List;

import com.it6666.domain.Menu;
import com.it6666.mapper.MenuMapper;
import com.it6666.service.MenuService;

/**
 * description: MenuServiceImpl
 * date: 2020-09-03 21:39
 * author: 30315
 * version: 1.0
 */
@Service
public class MenuServiceImpl implements MenuService {

    private final MenuMapper menuMapper;

    public MenuServiceImpl(MenuMapper menuMapper) {
        this.menuMapper = menuMapper;
    }

    @Override
    public List<Menu> selectMenuTree(boolean isAdmin, SimpleUser simpleUser) {
        QueryWrapper<Menu> qw = new QueryWrapper<>();
        qw.eq(Menu.COL_STATUS, Constants.STATUS_TRUE);
        qw.in(Menu.COL_MENU_TYPE, Constants.MENU_TYPE_M, Constants.MENU_TYPE_C);
        qw.orderByAsc(Menu.COL_PARENT_ID);
        if (isAdmin) {
            return menuMapper.selectList(qw);
        } else {
            // 根据用户id查询用户拥有的菜单信息
            return menuMapper.selectList(qw);
        }
    }
}

添加Shiro的配置

添加在 his-system/system-web/ 中的 src/main/java/com.it6666/config/shiro 文件夹中

package com.it6666.config.shiro;

import com.alibaba.fastjson.JSON;
import com.it6666.constants.HttpStatus;
import com.it6666.vo.AjaxResult;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

/**
 * description: 判断用户是否进行了登录
 * date: 2020-09-03 21:56
 * author: 30315
 * version: 1.0
 */
public class ShiroLoginFilter extends FormAuthenticationFilter {

    /**
     * 在访问controller前,判断是否登录,返回Json,不进行重定向
     *
     * @param request
     * @param response
     * @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json");
        AjaxResult ajaxResult = AjaxResult.fail();
        ajaxResult.put("code", HttpStatus.UNAUTHORIZED);
        ajaxResult.put("msg", "登录认证失效,请重新登录!");
        httpServletResponse.getWriter().write(JSON.toJSON(ajaxResult).toString());
        return false;
    }

}

创建TokenWebSessionManager

添加在 his-system/system-web/ 中的 src/main/java/com.it6666/config/shiro 文件夹中

package com.it6666.config.shiro;

import com.it6666.constants.Constants;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
import java.util.UUID;

/**
 * description: 生成token, 如果没有 token 生成一个返回到前台,如果有就从请求头里面取出来
 * date: 2020-09-03 22:05
 * author: 30315
 * version: 1.0
 */
@Configuration
public class TokenWebSessionManager extends DefaultWebSessionManager {
    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        // 从头里面得到请求TOKEN, 如果不存在就生成一个返回
        String header = WebUtils.toHttp(request).getHeader(Constants.TOKEN);
        if (StringUtils.hasText(header)) {
            return header;
        }
        return UUID.randomUUID().toString();
    }
}

创建ActiverUser

添加在 his-system/system-web/ 中的 src/main/java/com.it6666/vo 文件夹中

package com.it6666.vo;

import com.it6666.domain.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

/**
 * description: ActiverUser
 * date: 2020-09-03 22:11
 * author: 30315
 * version: 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ActiverUser implements Serializable {
    private User user;
    // 角色
    private List<String> roles = Collections.EMPTY_LIST;
    // 权限
    private List<String> permissions = Collections.EMPTY_LIST;
}

创建UserRealm

添加在 his-system/system-web/ 中的 src/main/java/com.it6666/config/shiro 文件夹中

package com.it6666.config.shiro;

import com.it6666.domain.User;
import com.it6666.service.UserService;
import com.it6666.vo.ActiverUser;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

/**
 * description: 自定义 realm 去匹配输入的用户名和密码
 * date: 2020-09-03 22:15
 * author: 30315
 * version: 1.0
 */
public class UserRealm extends AuthorizingRealm {
    @Autowired
    @Lazy
    private UserService userService;

    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }

    /**
     * 做认证, 就是登陆
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 得到用户登陆名
        String phone = token.getPrincipal().toString();
        // 根据电话查询用户是否存在
        User user = userService.queryUserByPhone(phone);
        // 查询到了说明用户存在,但是密码可能不正确
        if (null != user) {
            // 组装ActiverUser, 存放到 Reids 里面的对象
            ActiverUser activerUser = new ActiverUser();
            activerUser.setUser(user);
            // 匹配密码
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(activerUser, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), this.getName());
            return info;
        } else {
            // 返回null, 代表用户不存在
            return null;
        }
    }

    /**
     * 做授权, 登陆成功之后判断用户是否有某个菜单或按钮的权限
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 身份得到的就是上一个方法(SimpleAuthenticationInfo), 第一个参数 activerUser
        ActiverUser activerUser = (ActiverUser) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        return info;
    }
}

创建ShiroProperties

添加在 his-system/system-web/ 中的 src/main/java/com.it6666/config/shiro 文件夹中

package com.it6666.config.shiro;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * description: ShiroProperties
 * date: 2020-09-03 22:19
 * author: 30315
 * version: 1.0
 */
@ConfigurationProperties(prefix = "shiro")
@Data
public class ShiroProperties {
    /**
     * 密码加密方式
     */
    private String hashAlgorithmName = "md5";
    /**
     * 密码散列次数
     */
    private Integer hashIterations = 2;

    /**
     * 不拦击的路径
     */
    private String[] anonUrls;

    /**
     * 拦截的路径
     */
    private String[] authcUrls;
}

创建ShiroAutoConfiguration

添加在 his-system/system-web/ 中的 src/main/java/com.it6666/config/shiro 文件夹中

package com.it6666.config.shiro;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.IRedisManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * description: ShiroAutoConfiguration
 * date: 2020-09-03 22:20
 * author: 30315
 * version: 1.0
 */
@Configuration
@EnableConfigurationProperties(value = {ShiroProperties.class, RedisProperties.class})
public class ShiroAutoConfiguration {

    private ShiroProperties shiroProperties;

    private RedisProperties redisProperties;

    public static final String SHIRO_FILTER_NAME = "shiroFilter";

    public ShiroAutoConfiguration(ShiroProperties shiroProperties, RedisProperties redisProperties) {
        this.shiroProperties = shiroProperties;
        this.redisProperties = redisProperties;
    }

    /**
     * 创建凭证匹配器
     */
    @Bean
    public HashedCredentialsMatcher getHashedCredentialsMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        // 注入散列算法名
        matcher.setHashAlgorithmName(shiroProperties.getHashAlgorithmName());
        // 注入散列次数
        matcher.setHashIterations(shiroProperties.getHashIterations());
        return matcher;
    }

    /**
     * 创建自定义, realm
     * 并注入, 凭证匹配器
     */
    @Bean
    @ConditionalOnClass(value = {UserRealm.class})
    public UserRealm getUserRealm(HashedCredentialsMatcher matcher) {
        UserRealm userRealm = new UserRealm();
        // 注入, 凭证匹配器
        userRealm.setCredentialsMatcher(matcher);
        return userRealm;
    }

    /**
     * 创建安全管理器
     */
    @Bean
    @ConditionalOnClass(value = DefaultWebSecurityManager.class)
    public DefaultWebSecurityManager getSecurityManager(DefaultWebSessionManager defaultWebSessionManager, UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 注入, realm
        securityManager.setRealm(userRealm);
        securityManager.setSessionManager(defaultWebSessionManager);
        return securityManager;
    }

    /**
     * 声明过滤器
     * Shiro 的Web过滤器, id必须和 web.xml 里面的 shiroFilter的 targetBeanName 的值一样
     */
    @Bean(value = SHIRO_FILTER_NAME)
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        // 注入安全管理器
        bean.setSecurityManager(securityManager);
        // 处理用户未认证访问要认证的(资源)地址的跳转问题, 默认是跳转到, shiroProperties.getLoginUrl() 现在改成以 Json 串形式返回
        Map<String, Filter> filters = new HashMap<>();
        filters.put("authc", new ShiroLoginFilter());
        bean.setFilters(filters);

        Map<String, String> map = new HashMap<>();
        // 配置不拦截的路径
        String[] anonUrls = shiroProperties.getAnonUrls();
        if (anonUrls != null && anonUrls.length > 0) {
            for (String anonUrl : anonUrls) {
                map.put(anonUrl, "anon");
            }
        }
        // 配置拦截的路径
        String[] authcUrls = this.shiroProperties.getAuthcUrls();
        if (authcUrls != null && authcUrls.length > 0) {
            for (String authcUrl : authcUrls) {
                map.put(authcUrl, "authc");
            }
        }
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }


    /**
     * 注册DelegatingFilterProxy
     */
    @Bean
    public FilterRegistrationBean<DelegatingFilterProxy> registDelegatingFilterProxy() {
        // 创建注册器
        FilterRegistrationBean<DelegatingFilterProxy> bean = new FilterRegistrationBean<>();
        // 创建过滤器
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        // 注入过滤器
        bean.setFilter(proxy);
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName(SHIRO_FILTER_NAME);
        Collection<String> servleNames = new ArrayList<>();
        servleNames.add(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
        bean.setServletNames(servleNames);
        return bean;
    }


    /**
     * sessionManager 里面可以决定 sessionDAO
     *
     * @param redisSessionDao defaultWebSessionManager 来源 com.it6666.system.config.TokenWebSessionManager
     * @return
     */
    @Bean
    public DefaultWebSessionManager defaultWebSessionManager(RedisSessionDAO redisSessionDao) {
        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
        defaultWebSessionManager.setSessionDAO(redisSessionDao);
        return defaultWebSessionManager;
    }

    /**
     * 使用Redis, 来存储登录的信息
     * sessionDao 还需要设置给, sessionManager
     */
    @Bean
    public RedisSessionDAO redisSessionDAO(IRedisManager redisManager) {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        // 操作那个 Redis
        redisSessionDAO.setRedisManager(redisManager);
        // 用户的登录信息保存多久, 7天
        redisSessionDAO.setExpire(7 * 24 * 3600); 
        return redisSessionDAO;
    }

    /**
     * 因为分步式项目,所以使用 Redis 去存我们的登陆 Session
     *
     * @return
     */
    @Bean
    public IRedisManager redisManager() {
        // 因为 RedisManager 要操作 Redis 所以必须把Redis的客户端给RedisManager
        RedisManager redisManager = new RedisManager();
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, redisProperties.getHost(), redisProperties.getPort(), 5000, redisProperties.getPassword());
        redisManager.setJedisPool(jedisPool);
        return redisManager;
    }

    /**
     * 加入注解的使用,不加入这个注解不生效,开始
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
    // 加入注解的使用,不加入这个注解不生效,结束
}

LoginController

写登陆、退出、查询用户信息、接口

添加在 his-system/system-web/ 中的 src/main/java/com.it6666/controller/system 文件夹中

package com.it6666.controller.system;

import com.it6666.constants.Constants;
import com.it6666.constants.HttpStatus;
import com.it6666.domain.Menu;
import com.it6666.domain.SimpleUser;
import com.it6666.dto.LoginBodyDto;
import com.it6666.service.MenuService;
import com.it6666.vo.ActiverUser;
import com.it6666.vo.AjaxResult;
import com.it6666.vo.MenuTreeVo;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * description: LoginController
 * date: 2020-09-03 22:25
 * author: 30315
 * version: 1.0
 */
@RestController
@Log4j2
public class LoginController {

    private final MenuService menuService;

    public LoginController(MenuService menuService) {
        this.menuService = menuService;
    }

    /**
     * 登录方法
     *
     * @return 结果
     */
    @PostMapping("login/doLogin")
    public AjaxResult login(@RequestBody LoginBodyDto loginBodyDto, HttpServletRequest request) {
        AjaxResult ajax = AjaxResult.success();
        String username = loginBodyDto.getUsername();
        String password = loginBodyDto.getPassword();
        // 构造用户名和密码的 UsernamePasswordToken
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            // 得到会话的token, 也就是 Redis里面存的
            Serializable webToken = subject.getSession().getId();
            ajax.put(Constants.TOKEN, webToken);
        } catch (Exception e) {
            log.error("用户名或密码不正确", e);
            ajax = AjaxResult.error(HttpStatus.ERROR, "用户名或密码不正确");
        }
        return ajax;
    }

    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("login/getInfo")
    public AjaxResult getInfo() {
        Subject subject = SecurityUtils.getSubject();
        ActiverUser activerUser = (ActiverUser) subject.getPrincipal();
        AjaxResult ajax = AjaxResult.success();
        ajax.put("username", activerUser.getUser().getUserName());
        ajax.put("picture", activerUser.getUser().getPicture());
        ajax.put("roles", activerUser.getRoles());
        ajax.put("permissions", activerUser.getPermissions());
        return ajax;
    }

    /**
     * 用户退出
     *
     */
    @GetMapping("login/logout")
    public AjaxResult logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return AjaxResult.success("用户退出成功");
    }

    /**
     * 获取应该显示的菜单信息
     *
     * @return 菜单信息
     */
    @GetMapping("login/getMenus")
    public AjaxResult getMeuns() {
        Subject subject = SecurityUtils.getSubject();
        ActiverUser activerUser = (ActiverUser) subject.getPrincipal();
        boolean isAdmin = activerUser.getUser().getUserType().equals(Constants.USER_ADMIN);
        SimpleUser simpleUser = null;
        if (!isAdmin) {
            simpleUser = new SimpleUser(activerUser.getUser().getUserId(), activerUser.getUser().getUserName());
        }
        List<Menu> menus = menuService.selectMenuTree(isAdmin, simpleUser);
        List<MenuTreeVo> menuVos = new ArrayList<>();
        for (Menu menu : menus) {
            menuVos.add(new MenuTreeVo(menu.getMenuId().toString(), menu.getPath()));
        }
        return AjaxResult.success(menuVos);
    }
}

可以进行postman测试接口了,打开postman,我这里以yapi进行测试

接口数据校验

修改his-commons项目的pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

修改his-commons src/main/java/com/it6666/dto 中的 LoginBodyDto

@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginBodyDto implements Serializable {
    //  用户名
    @NotNull(message = "用户名不能为空")
    private String username;
    //  密码
    @NotNull(message = "用户密码不能为空")
    private String password;
    // 验证码
    private String code;
}

修改system-web的LoginController

在system-web com.it6666.exception 里创建GlobalExceptionHandler全局异常处理

package com.it6666.exception;

import com.it6666.vo.AjaxResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * description: GlobalExceptionHandler
 * date: 2020-09-03 23:54
 * author: 30315
 * version: 1.0
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 当系统出现MethodArgumentNotValidException这个异常时,会调用下面的方法
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public AjaxResult jsonErrorHandler(MethodArgumentNotValidException e) {
        return AjaxResult.error(e.getMessage());
    }
}

在system-web测试测试登陆方法

接口数据校验返回数据优化

system-web com.it6666.exception 里 GlobalExceptionHandler

package com.it6666.exception;

import com.it6666.vo.AjaxResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * description: 全局异常处理
 * date: 2020-09-03 23:54
 * author: 30315
 * version: 1.0
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 当系统出现MethodArgumentNotValidException这个异常时,会调用下面的方法
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public AjaxResult jsonErrorHandler(MethodArgumentNotValidException e) {
        List<Map<String, Object>> list = new ArrayList<>();
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        for (ObjectError allError : allErrors) {
            Map<String, Object> map = new HashMap<>();
            map.put("defaultMessage", allError.getDefaultMessage());
            map.put("objectName", allError.getObjectName());
            // 注意,这里面拿到的是具体的某一个属性
            FieldError fieldError = (FieldError) allError;
            map.put("field", fieldError.getField());
            list.add(map);
        }
        return AjaxResult.fail("后端数据校验异常", list);
    }
}

测试

全部通过,现在愉快的去写前端,注意一下,domain里面的实体必须实现序列化,不然会出现 Caused by: java.io.NotSerializableException 异常

posted @ 2020-09-03 23:42  BNTang  阅读(126)  评论(0编辑  收藏  举报