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);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_34274029/article/details/87426875