美文网首页Java技术升华小小程序员Spring-Boot
Spring Boot学习笔记(七)通用mapper,代码生成,

Spring Boot学习笔记(七)通用mapper,代码生成,

作者: Bug生活2048 | 来源:发表于2018-04-08 21:40 被阅读219次

    从零开始学习Spring Boot也有几天时间了,项目已经不允许我这么慢慢学习了,急需底层变现实现一套简单的Restful API用于业务支撑。

    于是在GitHub上找到了一个不错的demo,直接看demo搭建自己的项目了,这里记录下在搭建过程中学习到的和遇到的问题。

    先说说这个项目吧,项目结构,配置等非常精简,对于新手的我来说还是比较容易上手的,对于学习和开发很有帮助,给作者点赞。

    在此基础上做了点满足自身需求的改动,同时加入了swagger,顺利的搭建了一套服务。

    代码自动生成

    底层服务有很多通用的CRUD,利用代码生成最好不过了,这里作者将代码生成放在test中的 CodeGenerator,避免与正式代码冲突。

    生成的代码不细说了,大家可以慢慢理解,觉得有困难的可以直接拿过来用。

    主要通过org.mybatis.generator来实现,项目中的generator.template模板文件可以自行定义。

    Mybatis及分页插件配置

    首先引用分页插件包:

    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>4.2.1</version>
    </dependency>
    

    然后进行相应的配置:

    @Bean
    public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setTypeAliasesPackage(MODEL_PACKAGE);
    
        //配置分页插件,详情请查阅官方文档
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("pageSizeZero", "true");//分页尺寸为0时查询所有纪录不再执行分页
        properties.setProperty("reasonable", "true");//页码<=0 查询第一页,页码>=总页数查询最后一页
        properties.setProperty("supportMethodsArguments", "true");//支持通过 Mapper 接口参数来传递分页参数
        pageHelper.setProperties(properties);
    
        //添加插件
        factory.setPlugins(new Interceptor[]{pageHelper});
    
        //添加XML目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        factory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
        return factory.getObject();
    }
    

    通用Mapper配置

    引用通用mapper,简单的增删改查就不用再写对应的xml了,之后有新增字段只要修改对应的model就可以了,还是非常方便的。

    引用对应的包:

    <dependency>
        <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>3.4.2</version>
    </dependency>
    

    然后进行相应的配置:

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
        mapperScannerConfigurer.setBasePackage(MAPPER_PACKAGE);
    
        //配置通用Mapper,详情请查阅官方文档
        Properties properties = new Properties();
        properties.setProperty("mappers", MAPPER_INTERFACE_REFERENCE);
        properties.setProperty("notEmpty", "false");//insert、update是否判断字符串类型!='' 即 test="str != null"表达式内是否追加 and str != ''
        properties.setProperty("IDENTITY", "MYSQL");
        mapperScannerConfigurer.setProperties(properties);
    
        return mapperScannerConfigurer;
    }
    

    生成代码的实现

    在分页组件,通用mapper都配置完之后,我们需要通过自动生成,根据自定义模板生成我们所需要的ModelMapperMapperXMLServiceServiceImplController对应的基础代码。

    首先是模板的定义,定义常用的变量,定制你的代码,比如service模板,这样只要替换对应的变量就可以达到生成需要的代码的目的。

    package ${basePackage}.service;
    import ${basePackage}.model.${modelNameUpperCamel};
    import ${basePackage}.common.Service;
    
    /**
     * Created by ${author} on ${date}.
     */
    public interface ${modelNameUpperCamel}Service extends Service<${modelNameUpperCamel}> {
    
    }
    

    然后需要编写下基于通用MyBatis Mapper插件的Service接口的实现,从而在生成模板中根据该规则打通mapper与service层。

    public abstract class AbstractService<T> implements Service<T> {
    
        @Autowired
        protected Mapper<T> mapper;
    
        private Class<T> modelClass;    // 当前泛型真实类型的Class
    
        public AbstractService() {
            ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
            modelClass = (Class<T>) pt.getActualTypeArguments()[0];
        }
    
        public void save(T model) {
            mapper.insertSelective(model);
        }
    
        public void save(List<T> models) {
            mapper.insertList(models);
        }
    
        public void deleteById(Long id) {
            mapper.deleteByPrimaryKey(id);
        }
    
        public void deleteByIds(String ids) {
            mapper.deleteByIds(ids);
        }
    
        public void update(T model) {
            mapper.updateByPrimaryKeySelective(model);
        }
    
        public T findById(Long id) {
            return mapper.selectByPrimaryKey(id);
        }
    
        @Override
        public T findBy(String fieldName, Object value) throws TooManyResultsException {
            try {
                T model = modelClass.newInstance();
                Field field = modelClass.getDeclaredField(fieldName);
                field.setAccessible(true);
                field.set(model, value);
                return mapper.selectOne(model);
            } catch (ReflectiveOperationException e) {
                throw new ServiceException(e.getMessage(), e);
            }
        }
    
        public List<T> findByIds(String ids) {
            return mapper.selectByIds(ids);
        }
    
        public List<T> findByCondition(Condition condition) {
            return mapper.selectByCondition(condition);
        }
    
        public List<T> findAll() {
            return mapper.selectAll();
        }
    }
    

    具体的详细代码可以看下demo。

    统一响应结果和异常处理

    在配置springMVC时,通过继承WebMvcConfigurerAdapter,重写对应的方法,实现我们一些定制化的需求。

    使用FastJson

    阿里的fstjson转化效率还是比较高的,我们统一替换:

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(SerializerFeature.WriteMapNullValue,//保留空的字段
                SerializerFeature.WriteNullStringAsEmpty,//String null -> ""
                SerializerFeature.WriteNullNumberAsZero);//Number null -> 0
        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(Charset.forName("UTF-8"));
        converters.add(converter);
    }
    

    统一异常处理

    统一异常捕获,在业务失败直接使用ServiceException("message")抛出,统一输出{"code":400,"message":"这里是错误消息"}

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        exceptionResolvers.add((request, response, handler, e) -> {
            Result result = new Result();
            if (e instanceof ServiceException) {//业务失败的异常,如“账号或密码错误”
                result.setCode(ResultCode.FAIL).setMessage(e.getMessage());
                logger.info(e.getMessage());
            } else if (e instanceof NoHandlerFoundException) {
                result.setCode(ResultCode.NOT_FOUND).setMessage("接口 [" + request.getRequestURI() + "] 不存在");
            } else if (e instanceof ServletException) {
                result.setCode(ResultCode.FAIL).setMessage(e.getMessage());
            } else {
                result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage("接口 [" + request.getRequestURI() + "] 内部错误,请联系管理员");
                String message;
                if (handler instanceof HandlerMethod) {
                    HandlerMethod handlerMethod = (HandlerMethod) handler;
                    message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s",
                            request.getRequestURI(),
                            handlerMethod.getBean().getClass().getName(),
                            handlerMethod.getMethod().getName(),
                            e.getMessage());
                } else {
                    message = e.getMessage();
                }
                logger.error(message, e);
            }
            responseResult(response, result);
            return new ModelAndView();
        });
    }
    

    统一拦截器

    可以通过重写addInterceptors方法来自定义拦截,比如说用户登录,token验证等。

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //具体实现
    }
    

    添加Swagger

    之前的文章有具体介绍配置Swagger,这里只要在之前的基础上在springMVC配置项下添加swagger资源即可:

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
    
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
    

    实现效果如下,基本单表的操作不需要你编写代码了:

    1.png

    项目的基本内容介绍到这里,具体的还是需要大家自行去看想代码,实际操作一下。

    总结

    看代码的学习效率还是比看书快的,多实践,实践完看原理,感觉这样最好。
    如果想获取对应的代码,可以关注我的公众号:Bug生活2048,回复SpringBoot就可以啦。

    相互学习,共同进步~

    相关文章

      网友评论

        本文标题:Spring Boot学习笔记(七)通用mapper,代码生成,

        本文链接:https://www.haomeiwen.com/subject/koamhftx.html