1:mybatis-plus
推荐理由:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 支持关键词自动转义:支持数据库关键词(order、key......)自动转义,还可自定义关键词
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
- 内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击
案例
// 配置查询条件
EntityWrapper<CaseAlipayOfflineAccount> accountWrapper = new EntityWrapper<>();
accountWrapper
.like(!StringUtils.isBlank(account),
"alipay_account", account)
.like(!StringUtils.isBlank(name), "alipay_name", name)
.like(!StringUtils.isBlank(aging), "aging", aging)
.eq(null != isOpen, "is_open", isOpen)
.eq("is_delete", 0);
Page page = this.selectPage(new Page<>(query.getCurrent(), query.getSize()), accountWrapper);
2:lombok
推荐理由:Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。例如开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护,当属性多时会出现大量的getter/setter方法,这些显得很冗长也没有太多技术含量,一旦修改属性,就容易出现忘记修改对应方法的失误。
Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。
example:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
Lombok有哪些注解
@Setter
@Getter
@Data
@Log(这是一个泛型注解,具体有很多种形式)
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@NonNull
@Cleanup
@ToString
@RequiredArgsConstructor
@Value
@SneakyThrows
@Synchronized
3:spring中的restTemplate
Spring RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率,
结合spring cloud ribbon和fegin起到很好的效果,同时使用httpClient工具的不可维护性的问题,httpClient得到的response需要大量的json解析,使得系统维护麻烦。
example:
package com.fahui.core.live.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fahui.common.exceptions.LawBizException;
import com.fahui.core.live.beans.channel.*;
import com.fahui.core.live.beans.vod.video.GetRequest;
import com.fahui.core.live.beans.vod.video.GetResponse;
import com.fahui.core.live.constants.LiveConstant;
import com.fahui.core.live.service.IFhLiveService;
import com.fahui.core.service.entity.FhLiveChannel;
import com.fahui.core.service.service.IFhLiveChannelService;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* @Description:
* @author:CAIYJ
* @Date:2018/7/21 10:14
*/
@Service
public class FhLiveServiceImpl implements IFhLiveService {
@Autowired
private IFhLiveChannelService liveChannelService;
@Autowired
@Qualifier("wyRestTemplate")
private RestTemplate restTemplate;
private static String prfixUrl = "https://vcloud.163.com";
@Override
public VodVideoListResponse vodVideoList(VodVideoListRequest request) throws Exception {
BaseResponseGeneric<VodVideoListResponse> response = restTemplate.exchange(prfixUrl+"/app/vodvideolist",
HttpMethod.POST,
new HttpEntity<>(request),
new ParameterizedTypeReference<BaseResponseGeneric<VodVideoListResponse>>() {
}).getBody();
checkResponseGeneric(response);
return response != null ? response.getRet() : null;
}
@Override
public boolean setCallback(SetCallbackRequest request) throws Exception {
BaseResponse response = restTemplate.postForObject(prfixUrl+"/app/record/setcallback", request, BaseResponse.class);
checkResponse(response);
return true;
}
@Override
public boolean merge(MergeRequest request) throws Exception {
BaseResponse response = restTemplate.postForObject(prfixUrl+"/app/video/merge", request, BaseResponse.class);
checkResponse(response);
return true;
}
@Override
public boolean resetRecord(ResetRecordRequest request) throws Exception {
BaseResponse response = restTemplate.postForObject(prfixUrl+"/app/channel/resetRecord", request, BaseResponse.class);
checkResponse(response);
return true;
}
@Override
public TransCodeAddressResponse transCodeAddress(TransCodeAddressRequest request) throws Exception {
BaseResponse response = restTemplate.postForObject(prfixUrl+"/app/transcodeAddress", request, BaseResponse.class);
checkResponse(response);
TransCodeAddressResponse transCodeAddressResponse = new TransCodeAddressResponse();
BeanUtils.populate(transCodeAddressResponse, response.getRet());
return transCodeAddressResponse;
}
@Override
public CallbackQueryResponse callbackQuery() throws Exception {
BaseResponse response = restTemplate.postForObject(prfixUrl+"/app/record/callbackQuery", null, BaseResponse.class);
checkResponse(response);
CallbackQueryResponse callbackQueryResponse = new CallbackQueryResponse();
BeanUtils.populate(callbackQueryResponse, response.getRet());
return callbackQueryResponse;
}
@Override
public boolean setupRecordInfo(SetupRecordInfoRequest request) throws Exception {
if (null == request) {
return false;
}
BaseResponse response = restTemplate.postForObject(prfixUrl+"/app/channel/setupRecordInfo", request, BaseResponse.class);
checkResponse(response);
QueryWrapper<FhLiveChannel> ew = new QueryWrapper<>();
ew.eq(StringUtils.isNotEmpty(request.getCid()), "cid", request.getCid());
FhLiveChannel liveChannel = new FhLiveChannel();
BeanUtils.copyProperties(liveChannel, request);
liveChannelService.update(liveChannel, ew);
return true;
}
@Override
public GetResponse getVideo(GetRequest request) throws Exception {
BaseResponseGeneric<GetResponse> response = restTemplate.exchange(prfixUrl+"/app/vod/video/get",
HttpMethod.POST,
new HttpEntity<>(request),
new ParameterizedTypeReference<BaseResponseGeneric<GetResponse>>() {
}).getBody();
checkResponseGeneric(response);
return response != null ? response.getRet() : null;
}
private void checkResponseGeneric(BaseResponseGeneric<?> response) throws Exception {
if (null == response) {
throw new LawBizException(602, "查询失败", null);
} else {
switch (response.getCode()) {
case 200:
return;
default:
throw new LawBizException(response.getCode(), response.getMsg(), null);
}
}
}
private void checkResponse(BaseResponse response) throws Exception {
if (null != response) {
switch (response.getCode()) {
case 200:
return;
default:
throw new LawBizException(response.getCode(), response.getMsg(), null);
}
} else {
throw new LawBizException(602, "查询失败", null);
}
}
}
4:hibernate-validator
理由:
1:使用注解的形式将参数校验与业务代码分离
2:定义通用的validator,切面的形式切入到业务代码中
3:结合spring boot中的全局异常捕捉,系统原理繁琐的入参校验
package com.fahui.liquidation.receiver.bean.po.example;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.List;
/**
* @Description:
* @author:CAIYJ
* @Date:2018/8/13 11:34
*/
@Data
public class ConstraintExample {
private Integer id;
//---------------------------------------------Bean Validation 中内置的 constraint-------------------------------------
/**
* 被注释的元素必须不为 null(任何对象的value不能为null)_
*/
@NotNull
private String name;
/**
* 被注释的元素必须为 true
*/
@AssertTrue
private Boolean assertTrue;
/**
* 被注释的元素必须为 false
*/
@AssertFalse
private Boolean assertFalse;
/**
* 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
*/
@Min(11)
private Integer min;
/**
* 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
*/
@Max(60)
private Integer max;
/**
* 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
*/
@DecimalMin("11")
private String decimalMin;
/**
* 注释的元素必须是一个数字,其值必须小于等于指定的最大值
*/
@DecimalMax("60")
private String decimalMax;
/**
* 被注释的元素的大小必须在指定的范围内
*/
@Size(min = 11, max = 60, message = "大小在11-60之間")
private String size;
/**
* 被注释的元素必须是一个数字,其值必须在可接受的范围内
*/
@Digits(integer = 11, fraction = 60, message = "范围在11-60之间")
private Integer digits;
/**
* 被注释的元素必须是一个过去的日期
*/
@Past(message = "被注释的元素必须是一个过去的日期")
private Date past;
/**
* 被注释的元素必须是一个将来的日期
*/
@Future(message = "被注释的元素必须是一个将来的日期")
private Date future;
@Pattern(regexp = "^[0-9]{4}-[0-9]{2}-[0-9]{2}$", message = "出生日期格式不正确")
private String birth;
//---------------------------------------------Hibernate Validator 附加的 constraint-------------------------------------
/**
* 被注释的元素必须是电子邮箱地址
*/
@Email(message = "须是电子邮箱地址")
private String email;
/**
* 被注释的字符串的大小必须在指定的范围内
*/
@Length(min = 11, max = 60, message = "字符串长度在11-60之间")
private String length;
/**
* 被注释的字符串的必须非空(集合对象的元素不为0,即集合不为空,也可以用于字符串不为null)
*/
@NotEmpty
private List<String> notEmpty;
@Range(min = 18, max = 30, message = "年龄限制在18-30岁之间")
private Integer age;
/**
* 被注释的字符串的必须非空
*/
@NotBlank(message = "字符必须非空")
private String notBlank;
}
package com.fahui.validator.example;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* @Description:不能存在空字符串
* @author:CAIYJ
* @Date:2018/8/16 16:57
*/
public class CannotContainSpacesValidator implements ConstraintValidator<CannotContainSpaces, String> {
private int len;
/**
* 初始参数,获取注解中length的值
*/
@Override
public void initialize(CannotContainSpaces arg0) {
this.len = arg0.length();
}
@Override
public boolean isValid(String str, ConstraintValidatorContext constraintValidatorContext) {
if (str != null) {
if (str.indexOf(" ") < 0) {
return true;
}
} else {
constraintValidatorContext.disableDefaultConstraintViolation();//禁用默认的message的值
//重新添加错误提示语句
constraintValidatorContext
.buildConstraintViolationWithTemplate("字符串不能为空").addConstraintViolation();
}
return false;
}
}
5:fastjson
理由:使用该jar中的消息转换,可以全局解决返给前端数据的问题
/**
* 增加消息转换器,将返回消息中的 null 转成空字符串
*
* @param converters
*/
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fjc = new FastJsonConfig();
//1、序列化重点
fjc.setSerializerFeatures(SerializerFeature.BrowserCompatible);
//是否输出值为null的字段,默认为false
fjc.setSerializerFeatures(SerializerFeature.WriteMapNullValue,
// Boolean字段如果为null,输出为false,而非null
SerializerFeature.WriteNullBooleanAsFalse,
// 字符类型字段如果为null,输出为”“,而非null
SerializerFeature.WriteNullStringAsEmpty,
// Number类型为空则输出0
SerializerFeature.WriteNullNumberAsZero,
// 禁止循环引用
SerializerFeature.DisableCircularReferenceDetect,
// List为空则输出[]
SerializerFeature.WriteNullListAsEmpty);
// fjc.setSerializeFilters((ValueFilter) (o, s, source) -> {
// if (source instanceof Date) {
// return ((Date) source).getTime() + "";
// }
// return source;
// });
fastJsonConverter.setFastJsonConfig(fjc);
List<MediaType> mediaTypes;
mediaTypes = Arrays.asList(
MediaType.APPLICATION_JSON_UTF8,
MediaType.TEXT_PLAIN,
MediaType.TEXT_HTML,
MediaType.TEXT_XML,
MediaType.APPLICATION_OCTET_STREAM);
fastJsonConverter.setSupportedMediaTypes(mediaTypes);
fastJsonConverter.setDefaultCharset(Charset.forName("UTF-8"));
converters.add(fastJsonConverter);
}
6:swagger
理由:你懂得。最讨厌写word版本的接口文档了。。。
example:
@ApiOperation(value = "删除角色信息", notes = "删除角色信息", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@RequestMapping(value = "remove/{id}")
public BaseRestVO<String> remove( @PathVariable Long id) throws Exception {
roloService.removeById(id);
return BaseRestVO.success("删除成功");
}
7:ELK
理由:一般大型系统是一个分布式部署的架构,不同的服务模块部署在不同的服务器上,问题出现时,大部分情况需要根据问题暴露的关键信息,定位到具体的服务器和服务模块,构建一套集中式日志系统,可以提高定位问题的效率。
一个完整的集中式日志系统,需要包含以下几个主要特点:
- 收集-能够采集多种来源的日志数据
- 传输-能够稳定的把日志数据传输到中央系统
- 存储-如何存储日志数据
- 分析-可以支持 UI 分析
- 警告-能够提供错误报告,监控机制
ELK提供了一整套解决方案,并且都是开源软件,之间互相配合使用,完美衔接,高效的满足了很多场合的应用。目前主流的一种日志系统。(es是个好东西)
8:hutool
理由:
Hutool是Hu + tool的自造词,前者致敬我的“前任公司”,后者为工具之意,谐音“糊涂”,寓意追求“万事都作糊涂观,无所谓失,无所谓得”的境界。
Hutool是一个Java工具包,也只是一个工具包,它帮助我们简化每一行代码,减少每一个方法,让Java语言也可以“甜甜的”。Hutool最初是我项目中“util”包的一个整理,后来慢慢积累并加入更多非业务相关功能,并广泛学习其它开源项目精髓,经过自己整理修改,最终形成丰富的开源工具集。(抄自作者简介),当然类似的也有Apache的commons包等
9:spring boot相关的starter和spring cloud
本人改过spring-data-elasticsearch,深知spring社区对elasticsearch封装的有多好。同时也是经历过原生elasticsearch java api代码转变到spring-data-elasticsearch的过程