springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理

springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理

自己学习springboot走的坑有点多,网上各种不靠谱资料整的也是头疼。所以自己整一个记录,总结踩坑经验。项目主要是针对接口服务的,即返回json格式数据的接口。如果是支持web的话还需要其它的配置,也踩过坑。就不在这边里面整了。


项目目录

工程用的是maven管理的,工程完整的目录如下。
springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第1张图片

完整pom文件

pom文件里有些多余的jar包,因为之前项目用到,懒得去掉了[doge]:

"http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4.0.0
  com.springboot.text01
  springboot_text01
  0.0.1-SNAPSHOT

    
       1.8
       1.5.6.RELEASE
       3.6.1
       UTF-8
       UTF-8
    

    
      org.springframework.boot
      spring-boot-starter-parent
      1.5.10.RELEASE
    

    
        
            org.mybatis
            mybatis
            3.4.0
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            1.1.1
        

        
        
          tk.mybatis
          mapper-spring-boot-starter
          1.1.0
        
          
        
            com.github.pagehelper
            pagehelper-spring-boot-starter
            0.1.0
        
        
        
             com.oracle
             ojdbc6
             11.2.0.1.0
        

        
        

      

      

    
         org.springframework.boot
         spring-boot-starter-aop
         
            
                 spring-boot-starter-logging
                 org.springframework.boot
             
         
     
     
            org.springframework.boot
            spring-boot-starter-web
            
                
                    logback-core
                    ch.qos.logback
                
                
                    logback-classic
                    ch.qos.logback
                
            
        
        
            org.springframework.boot
            spring-boot-starter-log4j2
            ${sb.version}
        
        
            com.fasterxml.jackson.jaxrs
            jackson-jaxrs-json-provider
            2.9.0
        
        
            com.alibaba
            fastjson
            1.2.35
           
        
             org.apache.httpcomponents
             httpclient
             4.5.2
         

         
             org.apache.httpcomponents
             httpcore
             4.4.6
         
         
              org.apache.commons
              commons-lang3
              3.5
          
            
                joda-time
                joda-time
                2.9.9
            
            
            org.springframework
                spring-webmvc
                4.3.9.RELEASE
            
            
            
                com.google.guava
                guava
                19.0
            
    


    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                ${sb.version}
                
                    true
                    com.springboot.application.ApiApplication
                    true
                
                
                    
                        package
                        
                            repackage
                        
                    
                
            
            
                org.apache.maven.plugins
                maven-antrun-plugin
                ${jdk.version}
                
                    
                        install
                        
                            run
                        
                    
                
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                ${mvn.compile.version}
                
                    ${jdk.version}
                    ${jdk.version}
                    ${project.build.sourceEncoding}
                
            
        
    

   
        
        
            test
            
                test
            
            
                
                    
                        src/main/resources/test
                    
                    
                        src/main/java
                        
                            **/*.properties
                            **/*.xml
                            **/*.yml
                        
                        
                        false
                    
                
            
        
        
        
            pro

            
                pro
            
            
                
                    
                        src/main/resources/pro
                    
                    
                        src/main/java
                        
                            **/*.properties
                            **/*.xml
                            **/*.yml
                        
                        
                        false
                    
                
            
        
        
        
            dev
            
                true
            
            
                dev
            
            
                
                    
                        src/main/resources/dev
                    
                    
                        src/main/java
                        
                            **/*.properties
                            **/*.xml
                            **/*.yml
                        
                        
                        false
                    
                
            
        
    


创建application.yml文件

其实.properties文件和.yml文件都差不多用哪个都ok,如果不懂转的话在网上搜下properties在线转yml就好。先写红框的信息就好。一步一步调,否则哪部整合错了不知道错哪里再去查那是很坑的。
springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第2张图片

# Server settings  
server:  
    port: 8080

创建基础工具类

springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第3张图片
- IdGen.java :id生成类

package com.springboot.util;

import java.util.Random;
import java.util.UUID;
public abstract class IdGen {
    //主键生成
    public static String uuid(){
        return UUID.randomUUID().toString().replace("-", "");
    }

    public static String randomString(int length){
        final Random r=new Random();

        char[] ch=new char[length];
        for(int i=0;iint n=r.nextInt(62);
            if(n<26)
                ch[i]=(char) ('a'+n);
            else if(n<52)
                ch[i]=(char) ('A'+n-26);
            else
                ch[i]=(char)('0'+n-52);
        }
        return new String(ch);
    }

    public static String randomNumString(int length){
        final Random r=new Random();

        char[] ch=new char[length];
        for(int i=0;iint n=r.nextInt(10);
            ch[i]=(char)('0'+n);
        }
        return new String(ch);
    }
}
  • EnumCodeMessage异常信息类
package com.springboot.web;

/**
 * 错误类型
 * @author lowby
 *
 */
public enum EnumCodeMessage {
    SUCCESS(0, "成功!"),
    FAIL(-1, "失败!"),
    EXCEPTION(-1, "服务器异常,请稍后再试"),
    DATEFORMATERR(1000,"日期格式异常"),
    MISSINGSERVLETREQUESTPARAMETER(1001,"参数缺失"),
    ERR(1002,"手动错误");
    private final int code;
    private final String message;

    private EnumCodeMessage(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}
  • JsonResult.java :接口用以返回json格式
package com.springboot.web;

import java.util.HashMap;
import java.util.Map;

/**
 * 返回结果封装
 * @author lowby
 *
 */
public class JsonResult {

    public final static int SUCCESS = 0;//0,成功;其他为失败
    public final static Map EMPTY = new HashMap<>();
    private int errCode = SUCCESS;//默认为成功
    private String msg = "";
    private Object data;

    /**
     * 封装一个正常的返回对象.
     *
     * @param resultData result object
     * @return {@link JsonResult}
     */
    public static JsonResult build(Object resultData) {
        JsonResult result = new JsonResult();
        result.setData(resultData);
        return result;
    }

    /**
     * 封装返回一个指定的对象. btw:Data对象为空字符串
     *
     * @param errCode int value of return code
     * @param msg     String value of message
     * @return {@link JsonResult}
     */
    public static JsonResult build(int errCode, String msg) {
        return build(errCode, msg, EMPTY);
    }

    /**
     * 返回通用对象.
     *
     * @param errCode    返回码
     * @param msg        返回信息
     * @param resultData 对象
     * @return {@link JsonResult}
     */
    public static JsonResult build(int errCode, String msg, Object resultData) {
        JsonResult result = new JsonResult();
        result.setErrCode(errCode);
        result.setMsg(msg);
        result.setData(resultData);
        return result;
    }

    /**
     * 封装返回一个指定的枚举类型
     *
     * @param codeMessage
     * @return {@link JsonResult}
     */
    public static JsonResult build(EnumCodeMessage codeMessage) {
        return build(codeMessage.getCode(), codeMessage.getMessage(), EMPTY);
    }

    /**
     * 封装返回一个指定的枚举类型和数据类型
     *
     * @param codeMessage
     * @param resultData
     * @return {@link JsonResult}
     */
    public static JsonResult build(EnumCodeMessage codeMessage, Object resultData) {
        return build(codeMessage.getCode(), codeMessage.getMessage(), resultData);
    }

    /**
     * 封装返回一个成功的对象.
     */
    public static JsonResult buildSuccess() {
        return JsonResult.build(SUCCESS, "successed");
    }

    public int getErrCode() {
        return errCode;
    }

    public void setErrCode(int retcode) {
        this.errCode = retcode;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

}
  • WebConfig.java :支持跨域访问(不支持跨域的去掉这个类就ok)
package com.springboot.web;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
 * 跨域处理
 * @author lowby
 *
 */
@Configuration  
public class WebConfig extends WebMvcConfigurerAdapter{

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

创建启动类

springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第4张图片

package com.springboot.application;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//@MapperScan(basePackages = {"com.springboot.*.dao"})//mapper包
@SpringBootApplication(scanBasePackages = {"com"})
public class ApiApplication {

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

创建测试类

springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第5张图片

package com.springboot.controller;

import org.springframework.web.bind.annotation.RestController;

import com.springboot.web.JsonResult;
/**
 * 测试类
 * @author lowby
 *
 */
@RestController
public class TextController {

    /**
     * springboot启动测试
     * @return
     */
    @RequestMapping("/start.shtml")
    public JsonResult startApi(){

        return JsonResult.build(0,"success");
    }

启动springboot访问测试

springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第6张图片

ok,springboot到此springboot启动没问题。

链接orcal,配置pagehelper+通用mapper

在application.yml添加配置,yml中的mapperLocations可以先不加。要注意各种包的对应路径。

  • 往application.yml新增内容(注意是新增)
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第7张图片

# SPRING PROFILES  
spring:         
    # DATASOURCE  
    datasource:  
        driverClass: oracle.jdbc.OracleDriver  
        url: #自己要连的orcal链接
        username: #orcal用户名
        password: #orcal密码  

# 通用mapper的所在接口名称 不只是包名
mapper:
    identity: ORCAL
    mappers: tk.mybatis.mapper.common.Mapper
# PAGEHELPER
pagehelper:
    helperDialect: oracle
    reasonable: true
    supportMethodsArguments: true
    pageSizeZero: true
    params: count=countSql  
# MYBATIS
mybatis:
    # 实体所在位置
    type-aliases-package: com.springboot.po
    # 数据库与实体字段大小写映射
    configuration:
        map-underscore-to-camel-case: true
        mapUnderscoreToCamelCase: true
  • 创建dao、po及service类
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第8张图片

  • Authz.java

package com.springboot.po;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * 用户账户信息
 * @author lowby
 *
 */
@Table(name="XHXT.AUTHZ")
public class Authz implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = -1471135287095361841L;
    @Id
    private String id;
    @Column(name = "MOBILE")
    private String mobile;
    @Column(name = "ACCOUNT_STATE")
    private int accountState;
    @Column(name = "CREATE_DATE")
    private Date createDate;
    @Column(name = "UPDATE_DATE")
    private Date updateDate;

    //get&set
}
  • AuthzService.java
package com.springboot.service;

import com.github.pagehelper.PageInfo;
import com.springboot.po.Authz;

public interface AuthzService {

    public PageInfo findAllAuthz();

}
  • AuthzService.java
package com.springboot.service.impl;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.springboot.business.dao.AuthzMapper;
import com.springboot.exception.TextException;
import com.springboot.po.Authz;
import com.springboot.service.AuthzService;
import com.springboot.util.IdGen;

@Service
public class AuthzServiceImpl implements AuthzService {

     @Autowired
     private AuthzMapper authzMapper;

    @Override
    public PageInfo findAllAuthz() {
         PageHelper.startPage(1,10);
         List list = authzMapper.selectAll();
         PageInfo page = new PageInfo<>(list);
        return page;
    }


}

  • AuthzMapper.java
package com.springboot.business.dao;



import java.util.List;

import org.apache.ibatis.annotations.Select;

import com.springboot.po.Authz;

import tk.mybatis.mapper.common.BaseMapper;

public interface AuthzMapper extends BaseMapper<Authz>{

}

  • 在TextController.java 注入AuthzService及新增测试方法

    @Autowired
    private AuthzService authzService;
    /**
     * pagehelper+通用mapper测试
     * @return
     */
    @RequestMapping("/index.shtml")
    public JsonResult index(){
        PageInfo authz = authzService.findAllAuthz();
        return JsonResult.build(0,"success",authz);
    }
  • 在ApiApplication.java开启@MapperScan(basePackages = {“com.springboot.*.dao”})//mapper包注解
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第9张图片

  • 启动项目测试接口
    这里写图片描述

  • tips:如果在这步调不通通常原因:
    1.application.yml中配置的路径和自己建的类路径不一致;
    2.ApiApplication.java里@MapperScan注解路径配置错误。

mybatis自定义xml支持

  • 新建AuthzMapper.xml文件
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第10张图片
"1.0" encoding="UTF-8" ?>
"-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
"com.springboot.business.dao.AuthzMapper" >
    "ResultMap" type="com.springboot.po.Authz" >
    "ID" property="id" jdbcType="VARCHAR" />
    "MOBILE" property="mobile" jdbcType="VARCHAR" />
    "ACCOUNT_STATE" property="accountState" jdbcType="INTEGER" />
    "CREATE_DATE" property="createDate" jdbcType="TIMESTAMP" />
    "UPDATE_DATE" property="updateDate" jdbcType="TIMESTAMP" />

  

   "Base_Column_List" >
    ID, MOBILE, ACCOUNT_STATE, CREATE_DATE, UPDATE_DATE
  

  


  • 在application.yml添加自定义mapper.xml路径
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第11张图片

  • 在TextController.java新增测试方法

/**
     * mapper以xml形式访问测试
     * @param mobile
     * @return
     */
    @RequestMapping("/findAuthzByExcemple.shtml")
    public JsonResult findAuthzByExcemple(Authz authz){
        Authz reAuthz = authzService.selectOneByExcemple(authz);
        return JsonResult.build(0,"success",reAuthz);
    }
  • 在server、serverImpl及AuthzMapper新增对应方法
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第12张图片

springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第13张图片

springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第14张图片

  • 启动项目测试
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第15张图片

  • tips:如果报异常
    1.检查application.yml是否添加
    mapperLocations: com/springboot/*/mapper/*Mapper.xml 信息,切和创建的Mapper.xml路径是否一致
    2.创建的Mapper.xml文件里的属性配置是否正确
    3.如果查询的库里没有记录页面可能会报错(因为我截的图是配置了全局异常处理的,后面会讲),最好先用库力存在的数据测试。

开启全局异常处理及事务回滚(懒得再细分了!)

  • 开启全局异常处理
    1.创建自定义异常类TextException.java
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第16张图片
package com.springboot.exception;

import com.springboot.web.EnumCodeMessage;

/**
 * 自定义异常
 * @author lowby
 *
 */
public class TextException extends RuntimeException  {


     /**
     * 
     */
    private static final long serialVersionUID = -472018763672214998L;

    public TextException(String msg) {
        this.code = EnumCodeMessage.ERR.getCode();
        this.msg = msg;
    }

    private int code;
    private String msg;

    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }


}

2.全局异常处理类GlobalExceptionHandler.java

package com.springboot.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.springboot.web.EnumCodeMessage;
import com.springboot.web.JsonResult;

/**
 * 全局异常处理类
 * @author lowby
 *
 */
@ControllerAdvice
public class GlobalExceptionHandler {

     private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理所有不可知的异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public JsonResult handleException(Exception e){
        LOGGER.error(e.getMessage(), e);
        return JsonResult.build(EnumCodeMessage.EXCEPTION);
    }

    /**
     * 处理业务异常
     * @param e
     * @return
     */
    @ExceptionHandler(TextException.class)
    @ResponseBody
    public JsonResult handleTextException(TextException e){
        LOGGER.error(e.getMsg(), e);
        return JsonResult.build(e.getCode(),e.getMsg());
    }

    /**
     * 请求参数缺失异常
     * @param e
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public JsonResult handleMissingServletRequestParameterException(MissingServletRequestParameterException e){
        LOGGER.error(e.getMessage(), e);
        return JsonResult.build(EnumCodeMessage.MISSINGSERVLETREQUESTPARAMETER.getCode(),e.getMessage());
    }

}

  • 全局事务配置
    1.全局事务控制TransactionAdviceConfig.java
package com.springboot.web;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

/**
 * 事务控制
 * @author lowby
 *
 */
@Aspect
@Configuration
public class TransactionAdviceConfig {


    private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.springboot.service..*.*(..))";

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Bean
    public TransactionInterceptor txAdvice() {

        DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
        txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
        txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        txAttr_REQUIRED_READONLY.setReadOnly(true);

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        source.addTransactionalMethod("*", txAttr_REQUIRED);//全部开启读写事务
       /* source.addTransactionalMethod("delete*", txAttr_REQUIRED);
        source.addTransactionalMethod("update*", txAttr_REQUIRED);
        source.addTransactionalMethod("exec*", txAttr_REQUIRED);
        source.addTransactionalMethod("set*", txAttr_REQUIRED);
        source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);*/

        return new TransactionInterceptor(transactionManager, source);
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
}
  • 新增测试方法及对应service方法
    1.TaxtController.java 新增方法
/**
     * 事务控制测试
     * @param mobile
     * @return
     */
    @RequestMapping("/findAuthz.shtml")
    public JsonResult findAuthzByMobile(@RequestParam(value="mobile",required=true)String mobile){

        Authz authz = authzService.findAuthzByMobile(mobile);
        return JsonResult.build(0,"success",authz);
    }

2.AuthzService.java 新增方法

public Authz findAuthzByMobile(String mobile);

3.AuthzServiceImpl.java 新增方法

@Override
    public Authz findAuthzByMobile(String mobile) {

        Authz authz = authzMapper.findAuthzByMobile(mobile);
        if(Objects.isNull(authz)){
            Authz record = new Authz();
            record.setId(IdGen.uuid());
            record.setCreateDate(new Date());
            record.setUpdateDate(new Date());
            record.setMobile(mobile);
            authzMapper.insertSelective(record);
            throw new TextException("我靠,保存出错了");//没有注掉却能保存成功的说明事务控制有问题
        }
        return authz;
    }

4.AuthzMapper.java新增方法


    @Select("select * from XHXT.AUTHZ where mobile = #{mobile}")
    Authz findAuthzByMobile(String mobile);
  • 运行程序测试
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第17张图片
    查询库里未保存成功,同时抛出了自定义异常,说明配置成功可以开始码项目代码了。
    springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理_第18张图片

  • tips:事务不成功注意查看TransactionAdviceConfig.java类里配置的AOP_POINTCUT_EXPRESSION是否与需要开启事务类所在的包。

总结

以上是踩完坑后倒叙回溯写的,有可能有些环节是后面已经配制了,导致按顺序调的时候有可能报的错不一致,可以看下是不是那些东西后面配置的。emmmmm…就酱!


你可能感兴趣的:(springboot+mybatis+orcale+pagehelper+通用mapper+开启全局事务+异常统一处理)