SpringBoot干货学习总结

1. 实体类

  1. 动态更新数据,只更新有值的数据

@DynamicUpdate

  1. 将实体类映射为表,如果名字不匹配使用name=tablename

@Entity

  1. 将属性映射为主键,并设置自增

@Id @GenericValue

  1. 自动生成常用方法

@Data @Getter @Setter
安装lombok教程

  1. 该属性不会映射到库里

@Transient

  1. 不希望返回JSON的属性

@JsonIgnore

  1. 只返回非空的JSON

@JsonInclude

  1. 将JSON转换为List

gson.fromJSON(json,new TypeToken<List<T>>(){}.getType());

  1. 将日期转换为Long做法:新建一个类如下,再将实体类日期属性上加

@JsonSerialize(using=Date2LongSerializer.class)

public class Date2LongSerializer extends JsonSerializer<Date> {
    @Override
    public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        jsonGenerator.writeNumber(date.getTime() / 1000);
    }
}
  1. 添加额外配置文件

@ImportResource({"classpath:xxx-context.xml","classpath:yyy-context.xml"})

  1. 添加额外属性文件

@PropertyResource({"classpath:xxx.properties","classpath:yyy.properties"})

  1. 读取属性文件,配置类型安全的bean

@Component
@ConfigurationProperties(prefix="book",location={"classpath:config/book.properties"})


2. 持久层

点击查看JPA语法

//创建持久层接口
//继承JpaRepository<对象,主键>自带基本的增删改查功能
//如果有特殊查询,请按照给定的语法,写出方法即可
//语法规则
public interface ProductInfoRepository extends JpaRepository<ProductInfo, String> {
    List<Object> findByObjIdIn(List<Integer> idList);
}
  • 更多内容参考第9章

2. 业务层

  1. 接口+实现类的方式

public interface DemoService {
//根据id获得对象
Object findOne(Integer id);
//获得所有对象,JPA会根据实体的相关注解进行查询
List<Object> findAll();
//根据给定的id集合,查找符合条件的对象集合
List<Object> findByObjIdIn(List<Integer> idList);
}

@Service
public class DemoServiceImpl implements DemoService {
    //注入DAO层
    @Autowired
    private CtsDAO dao;
    //实现方法的业务逻辑
    @Override
    public Object findById(Integer id) {
        return dao.findById(id);
    }

}

3. 控制层

  1. 类级注解

@RestController(返回Json格式专用) @RequestMapping("/*/*")

  1. 方法级注解

@GetMapping("/list")@PostMapping("/list")
@PutMapping() @DeleteMapping()

  1. 参数级注解

@RequestParam(value="id",defaultValue="1")String id
required=false,参数可为空

//get请求示例
@GetMapping("/list")
//指定参数和默认值
public ModelAndView list(@RequestParam(value="id",defaultValue="1")String id, Map<String, Object> map) {
    List<ProductCategory> categoryList = categoryService.findAll();
    
    //将数据放到map里
    map.put("categoryList", categoryList);
    //返回视图和map,供解析
    return new ModelAndView("category/list", map);
}

//post请求示例
//使用表单验证类接收表单
@PostMapping("/save")
public ModelAndView save(@Valid CategoryForm form, BindingResult bindingResult, Map<String, Object> map) {

    //...处理逻辑

    //保存对象
    service.save(productCategory);
    //返回视图名和需要绑定的数据
    return new ModelAndView("common/success", map);
}

//分页请求示例
 /**
 * 列表
 * @param page 第几页, 从1页开始
 * @param size 一页有多少条数据
 * @return
 */
@GetMapping("/list")
public ModelAndView list(@RequestParam(value = "page", defaultValue = "1") Integer page,
                         @RequestParam(value = "size", defaultValue = "10") Integer size,
                         Map<String, Object> map) {
    //分页请求对象(页码从0开始)              
    PageRequest request = new PageRequest(page - 1, size);
    Page<OrderDTO> orderDTOPage = service.findList(request);
    //将查询结果放入ModelAndView
    map.put("orderDTOPage", orderDTOPage);
    map.put("currentPage", page);
    map.put("size", size); 
    return new ModelAndView("order/list", map);
}
  • 以下为前后端分离写法,直接返回Json格式的数据

//通过接口返回值(前后端分离)
@GetMapping("/detail")
public ResultVO<OrderDTO> detail(@RequestParam("id") String id ) {
OrderDTO orderDTO = service.findOne(id);
return ResultVOUtil.success(orderDTO);
}

//返回值工具类
public class ResultVOUtil {
    public static ResultVO success(Object object) {
        ResultVO resultVO = new ResultVO();
        resultVO.setData(object);
        resultVO.setCode(0);
        resultVO.setMsg("成功");
        return resultVO;
    }
    public static ResultVO success() {
        return success(null);
    }
    public static ResultVO error(Integer code, String msg) {
        ResultVO resultVO = new ResultVO();
        resultVO.setCode(code);
        resultVO.setMsg(msg);
        return resultVO;
    }
}

@Data
public class ResultVO<T> {
    /** 错误码. */
    private Integer code;
    /** 提示信息. */
    private String msg;
    /** 具体内容. */
    private T data;
}

4. 表单验证类

  1. 建立一个实体验证类@Data @NotEmpty(message= "必填")非空验证
  2. 在controller接收方法参数里加上@Valid 验证类 用BindingResult对象接收结果

@PostMapping("/create")
public ResultVO<Map<String, String>> create(@Valid OrderForm orderForm, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
log.error("【创建订单】参数不正确, orderForm={}", orderForm);
throw new SellException(ResultEnum.PARAM_ERROR.getCode(), bindingResult.getFieldError().getDefaultMessage());
}
}


5. 测试类

  1. 类级注解

@RunWith(SpringRunner.class) @SptingBootTest @Slf4j

  1. 测试完毕就回滚 测试方法注解

@Test @Transactional

  1. 日志打印方法详情如下

    log.debug("debug...");
    log.info("name: " + name + " ,password: " + password);
    log.info("name: {}, password: {}", name, password);
    log.error("error...");
    log.warn("warn...");

  2. 拷贝属性BeanUtils.copyProperties(from,to)


6. AOP类

  1. 建立aop类,添加类级注解

@Aspect@Component

  1. 创建处理逻辑方法注解如下:先定义切入点,再对切入点操作

     @PointCut("execution(public * com.xs.controller.RelateController.list(..))")
    public void log(){}切入点
    @Before("log()")最先拦截
    @After("log()")最后拦截
    @AfterReturning("log()")结果通知
    @AfterThrowing("log()")异常通知
    @Around("log()")环绕通知
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{  
     System.out.println("进入环绕通知");  
     Object object = pjp.proceed();//执行该方法  
     System.out.println("退出方法");  
     return object;  
    }  
    顺序:最先拦截>环绕入>log()>结果通知>环绕出>最后拦截
    
  2. 使用日志打印控制台:

     private static final Logger logger = LoggerFactory.getLogger(类名.class)
     logger.info("XXX")
    

7. 枚举类

  • 要点
  1. 一般有两个属性code,message,并加上@Getter注解
  2. 共有的方法提取到一个Integerface中实现
  3. 通过使用枚举类得到信息,例如数据库里是0和1,要得到对应的是和否,可通过如下几段代码
//步骤一
//首先要有一个枚举类
//继承下段代码接口
@Getter
public enum ResultEnum extends CodeEnum{
    SUCCESS(0, "是"),
    PARAM_ERROR(1, "否"),
    ;

    private Integer code;

    private String message;
    //通过构造方法
    ResultEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}



//提取获得枚举类共有方法
public interface CodeEnum<T> {
    T getCode();
}

//此工具类用于根据0和1来获取枚举常量
public class EnumUtil {
    public static <T extends CodeEnum> T getByCode(Integer code, Class<T> enumClass) {
        for (T each: enumClass.getEnumConstants()) {
            if (code.equals(each.getCode())) {
                return each;
            }
        }
        return null;
    }
}


//在对象里调用工具类,通过自身属性status来获取枚举常量
@JsonIgnore
public ResultEnum getResultEnum() {
    return EnumUtil.getByCode(status, ResultEnum.class);
}

//最终在页面渲染时,通过这样来获取
${obj.getResultEnum.message}

8. 异常类

  • 要点
  1. 继承RuntimeException
  2. 要有一个属性记录错误代码
  3. 可供传入枚举类的构造器,调用父类构造方法传递异常信息
//自定义异常类
public class SellException extends RuntimeException{
    //记录异常代码
    private Integer code;
    //该构造器用来传入枚举类
    public SellException(ResultEnum resultEnum) {
        super(resultEnum.getMessage());
        this.code = resultEnum.getCode();
    }
    //该构造器用来传入异常代码和异常信息
    public SellException(Integer code, String message) {
        super(message);
        this.code = code;
    }
}

//自定义全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value=Exception.class)
    @ResponseBody
    private Map<String,Object> exceptionHandler(HttpServletRequest req,Exception e){
        Map<String,Object> map = new HashMap<>();
        map.put("success", false);
        map.put("errMsg", e.getMessage());
        return map;
    }
}

//调用方式
if (orderDTO == null) {
    log.error("【取消订单】查不到改订单, orderId={}", orderId);
    throw new SellException(ResultEnum.ORDER_NOT_EXIST);
}

9. Springboot兼容MyBatis

  1. 引入依赖
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.9</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.29</version>
</dependency>

添加配置文件
# mybatis
# 与表关联的对象所在包
mybatis.type-aliases-package=com.ctsmgr.entity 
# 下划线转驼峰
mybatis.configuration.map-underscore-to-camel-case=true
# mapper.xml所在目录
mybatis.mapperLocations = classpath:com/dao/*.xml
mybatis.configuration.default-statement-timeout=3000
mybatis.configuration.default-fetch-size=100
# druid
spring.datasource.url=jdbc:mysql://localhost/blog?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.filters=stat
spring.datasource.maxActive=2
spring.datasource.initialSize=1
spring.datasource.maxWait=60000
spring.datasource.minIdle=1
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=select 'x'
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxOpenPreparedStatements=20
  1. 启动类

  2. 写一个mapper接口,注解sql的方式,该方法名可自定义,执行的方法由注解传入,如:

//插入方式一:传递Map(参数名称对应KEY值)
@Mapper
public interface ProductMapper{
@Insert(insert into CTS_RELATE_COMPANY (rela_comp_id,rela_comp_name) values(#{relaCompId,jdbcType=Integer},#{relaCompName,jdbcType=VARCHAR}))
int insertByMap(Map<String,Object> map);
}

//插入方式二:传递对象(参数名称对应属性名称)
@Mapper
public interface ProductMapper{
@Insert("insert into CTS_RELATE_COMPANY (rela_comp_id,rela_comp_name) values(#{relaCompId,jdbcType=Integer},#{relaCompName,jdbcType=VARCHAR})")
int insertByObject(CtsRelateCompany ctsRelateCompany);
}
//查询,如果返回多条记录用List接收
@Select("select * from CTS_RELATE_COMPANY where rela_comp_id = #{relaCompId}")
@Results({
@Result(Column="rela_comp_id",property="relaCompId"),
@Result(Column="rela_comp_name",property="relaCompName"),
})
List<CtsRelateCompany> findById(Integer id);

//修改方式一:传递多参数,多个参数时需添加@Param注解
@Update("update CTS_RELATE_COMPANY set rela_comp_name = #{relaCompName} where rela_comp_id = #{relaCompId}")
int updateById(@Param("relaCompName")String name,@Param("relaCompId")Integer id);
//修改方式二:传递对象
@Update("update CTS_RELATE_COMPANY set rela_comp_name = #{relaCompName} where rela_comp_id = #{relaCompId}")
int updateByObject(CtsRelateCompany ctsRelateCompany);
//删除:
@Delete("delete from CTS_RELATE_COMPANY where rela_comp_id = #{relaCompId}")
int deleteById(Integer relaCompId);

  1. 如何调用Mapper?

//首先建立dao层
public class CtsRelateCompanyDAO{
@Autowired
CtsRelateCompanyDao dao;
public int insertByName(Map<String,Object> map){
return dao.insertByName(map);
}
}
//在service层里注入DAO并调用

  1. 返回主键

@Options(useGeneratedKeys=true, keyProperty="id",keyColumn="id")

10. 配置多数据源

  1. 配置属性文件

master 数据源配置
spring.datasource.url=jdbc:mysql://localhost/blog?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456

spring.datasource.driverClassName=com.mysql.jdbc.Driver

slave 数据源配置
spring.datasource2.url=jdbc:mysql://localhost/blog2?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
spring.datasource2.username=root
spring.datasource2.password=123456
spring.datasource2.driverClassName=com.mysql.jdbc.Driver

  1. 实例化多个数据源(指定一个主数据源,并添加@Primary)
//主数据源配置类
@Configuration
//扫描mapper所在包
@MapperScan("springboot.start.db.company1.mapper")
public class MysqlDataSource1Config {
        //实例化数据源
    @Bean(name = "primaryDataSource")
    @Primary
    @ConfigurationProperties(prefix="spring.datasource")
    public DataSource dataSource(){
        return DataSourceBuilder.create().build();
    }
    //实例化工厂类,并注入数据源
    @Bean(name="primarySqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        return sessionFactory.getObject();
    }
}
//从数据源
@Configuration    @MapperScan(basePackages="springboot.start.db.company2.mapper",sqlSessionFactoryRef="secondSqlSessionFactory")
public class MysqlDataSource2Config {
    @Bean(name = "secondDataSource")
    @ConfigurationProperties(prefix="spring.datasource2")
    public DataSource dataSource(){
        return DataSourceBuilder.create().build();
    }
    @Bean(name = "secondSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        return sessionFactory.getObject();
    }
}

//配置完毕,直接注入即可使用
@RestController
public class DbController {
    @Autowired
    private UserMapper dao;
    
    @Autowired
    private UserMapper2 dao2;
    
    @GetMapping("/find/{id}")
    public User find(@PathVariable("id")int id) {
        return dao.findById(id);
    }
    @GetMapping("/find2/{id}")
    public User find2(@PathVariable("id")int id) {
        return dao2.findById(id);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,656评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,810评论 6 342
  • 比如我们要实现这样一个组件,就是一个输入框里面字数的计数。 为了更清楚的演示,下面全部使用jQuery作为基础语言...
    209bd3bc6844阅读 621评论 0 1
  • 【1】 景弘学校招生会有感 今天上午9点参加了景弘学校招生会。景弘校长做了深刻的演讲,这是目前关于对孩子当下学习情...
    走向阳光的自己阅读 293评论 1 7
  • 1.人参味甘,大补元气,止咳生津,调容养卫。 2.黄芪性温,收汗固表,托疮生肌,气虚莫少。 3.白术甘温,健脾强胃...
    天一书社阅读 688评论 0 0