Spring Boot學習筆記(七)通用mapper,代碼生成,分頁組件接入

從零開始學習Spring Boot也有幾天時間了,項目已經不容許我這麼慢慢學習了,急需底層變現實現一套簡單的Restful API用於業務支撐。

因而在GitHub上找到了一個不錯的demo,直接看demo搭建本身的項目了,這裏記錄下在搭建過程當中學習到的和遇到的問題。html

先說說這個項目吧,項目結構,配置等很是精簡,對於新手的我來講仍是比較容易上手的,對於學習和開發頗有幫助,給做者點贊。git

在此基礎上作了點知足自身需求的改動,同時加入了swagger,順利的搭建了一套服務。github

代碼自動生成

底層服務有不少通用的CRUD,利用代碼生成最好不過了,這裏做者將代碼生成放在test中的 CodeGenerator,避免與正式代碼衝突。web

生成的代碼不細說了,你們能夠慢慢理解,以爲有困難的能夠直接拿過來用。spring

主要經過org.mybatis.generator來實現,項目中的generator.template模板文件能夠自行定義。sql

Mybatis及分頁插件配置

首先引用分頁插件包:json

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

而後進行相應的配置:api

@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就能夠了,仍是很是方便的。mybatis

引用對應的包:app

<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就能夠啦。

相互學習,共同進步~

相關文章
相關標籤/搜索