自己学习springboot走的坑有点多,网上各种不靠谱资料整的也是头疼。所以自己整一个记录,总结踩坑经验。项目主要是针对接口服务的,即返回json格式数据的接口。如果是支持web的话还需要其它的配置,也踩过坑。就不在这边里面整了。
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}
${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
其实.properties文件和.yml文件都差不多用哪个都ok,如果不懂转的话在网上搜下properties在线转yml就好。先写红框的信息就好。一步一步调,否则哪部整合错了不知道错哪里再去查那是很坑的。
# Server settings
server:
port: 8080
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);
}
}
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;
}
}
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;
}
}
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("/**");
}
}
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);
}
}
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");
}
ok,springboot到此springboot启动没问题。
在application.yml添加配置,yml中的mapperLocations可以先不加。要注意各种包的对应路径。
# 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
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
}
package com.springboot.service;
import com.github.pagehelper.PageInfo;
import com.springboot.po.Authz;
public interface AuthzService {
public PageInfo findAllAuthz();
}
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;
}
}
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>{
}
@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包注解
tips:如果在这步调不通通常原因:
1.application.yml中配置的路径和自己建的类路径不一致;
2.ApiApplication.java里@MapperScan注解路径配置错误。
"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
/**
* mapper以xml形式访问测试
* @param mobile
* @return
*/
@RequestMapping("/findAuthzByExcemple.shtml")
public JsonResult findAuthzByExcemple(Authz authz){
Authz reAuthz = authzService.selectOneByExcemple(authz);
return JsonResult.build(0,"success",reAuthz);
}
tips:如果报异常
1.检查application.yml是否添加
mapperLocations: com/springboot/*/mapper/*Mapper.xml 信息,切和创建的Mapper.xml路径是否一致
2.创建的Mapper.xml文件里的属性配置是否正确
3.如果查询的库里没有记录页面可能会报错(因为我截的图是配置了全局异常处理的,后面会讲),最好先用库力存在的数据测试。
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());
}
}
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());
}
}
/**
* 事务控制测试
* @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);
tips:事务不成功注意查看TransactionAdviceConfig.java类里配置的AOP_POINTCUT_EXPRESSION是否与需要开启事务类所在的包。
以上是踩完坑后倒叙回溯写的,有可能有些环节是后面已经配制了,导致按顺序调的时候有可能报的错不一致,可以看下是不是那些东西后面配置的。emmmmm…就酱!