【java架构搭建】之gradle基础包
我们的目标是把业务与技术进行拆解隔离。
不会因为技术组件的升级,需要大量的修改代码。
所以我们会选择把一些比较独立常用的技术或业务功能切分成独立微服务。
这些微服务要用到的一些通性需求如:
出入参封装
异常处理
一些工具类
需要写到基础包里。
软件架构
构建工具:gradle
安装教程
idea:
- File->Settings->Build->Build Tools->Gradle->Use Gradle from:Specified location 选你gradle路径 E:/gradle/gradle-7.0
- 根目录下对着build.gradle右键 import Gradle project 右边出现Gradel工具栏窗口
- Gradel工具栏窗口,根下->Tasks->publishing->publishMavenJavaPublicationToMavenLocal(发布到本机仓库)
- 发布到私服:修改 build.gradle文件 repositories.maven中的url地址到你的私服,
修改gradle.properties文件 nexus_username和nexus_password
Gradel工具栏窗口,根下->Tasks->publishing->publishMavenJavaPublicationToNexusRepository
目录结构
- cpe-util:常用工具类
- cpe-bizapi:静态常量定义
- cpe-bizimpl:切面、出入参基类
- cpe-starters.cpe-starters:cpe-web-starter:搭建web项目需要的一些包引用
- cpe-starters.cpe-starters:cpe-db-starter:连数据库需要的一些包引用
使用说明
在你的web项目中,先引入:
dependency 'com.cairh:cpe-web-starter:0.0.1-beta.5'
dependency 'com.cairh:cpe-db-starter:0.0.1-beta.5'
- 切面
名称 英文名 功能说明 环境清理切面 ContextClearAspect 清理线程绑定的公共参数 生成请求编号切面 RequestNumberAspect 生成request_id 绑定参数切面 VOBindAspect 绑定入参的某些字段到线程参数中
同时也可以补充出入参
如:把trace_id(痕迹唯一码)放到入参中,把trace_id放到出参中错误描述处理切面 ErrorDescAspect 根据配置填写error_no对应的错误信息error_info
将一些外部错误号转换成内部错误号和内部错误信息异常处理切面 ExceptionHandleAspect 捕获方法中的异常,包装到error_info中去 参数验证切面 ValidateAspect 通过标注的注解,验证入参,不合法将自动返回错误信息
在自己的项目中写一个配置类
@Aspect
@Configuration
@EnableAspectFrameConfig
public class AspectConfig {
private boolean isOpenAspect = true;
@Autowired
private List<AspectInterceptor> interceptors;
//请修改下面的包路径到你的controller包 或 svc的rpc包
@Pointcut("execution(public * com.xxx.demo.controller..*.*(..))")
public void rpcAll() {
}
@Around("rpcAll()")
public Object Interceptor(ProceedingJoinPoint pjp) throws Throwable {
if (isOpenAspect) {
Iterator<AspectInterceptor> interceptorIt = interceptors.iterator();
return AspectInterceptorUtil.callNextInterceptor(interceptorIt, pjp);
}
return pjp.proceed();
}
//调用其它微服务的类所在的包,如果没有请注释以下部分
@Pointcut("execution(public * com.xxx.demo.remoteservice.feignimpl..*.*(..))")
public void nextMs() {
}
@Around(value = "nextMs()")
public Object round(ProceedingJoinPoint joinPoint) {
VOBeanBase vo = null;
for (Object arg : joinPoint.getArgs()) {
if (arg instanceof VOBeanBase) {
vo = (VOBeanBase) arg;
vo.setProtocol("http");
VOUtil.setPubParamForNextLayer(vo);
}
}
Object obj = null;
try {
obj = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return obj;
}
}
上面的包路径请根据你的实际情况修改。就像用Swagger2Config一样。 其它部分不用改。
如果你是提供http服务的请指向controller包,如果你是提供dubbo服务的请指向rpc包。
- 入参
请继承于:VOBeanBase
toString用json
@ApiModel(description= "上传Base64图片")
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class UploadBase64Param extends VOBeanBase {
@ApiModelProperty(value = "图片的Base64字符串", required = true)
@NotBlank
private String imageBase64;
@ApiModelProperty(value = "存到桶下的路径", required = false)
private String dir;
@Override
public String toString(){
return JSON.toJSONString(this);
}
}
翻页请继承于:PageInfoVo
@Data
@EqualsAndHashCode(callSuper = false)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class QueryEventParam extends PageInfoVo{
@ApiModelProperty(value = "任务运行方式")
private String onlyTaskFlag;
}
入参验证注解:
@Data
@EqualsAndHashCode(callSuper = false)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DemoParam extends PageInfoVo {
@NotBlank //不能为空串
private String a;
@NotNull //不能为空
private Integer b;
@NotBlank //不能为空串
@ApiModelProperty(value = "事件运行状态")
//指定字典与字典值的获取方法名
@EnumValue(enumClass = Dict100008.class, getValMethodName = "getSubEntry")
private String etlEventStatus;
@ApiModelProperty(value = "开始运行任务的最小时间")
//日期格式验证
@DateValue(pattern = DateTimeUtil.FORMAT_YYYYMMDD_NO_BREAK)
private java.lang.Long minDateForStart;
}
不够的可以自己加各种验证类。
- 出参
请将要返回的业务数据包装成对象:
@ApiModel(description= "运行事件信息")
@SuppressWarnings("serial")
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EventDto implements Serializable {
@ApiModelProperty(value = "触发事件id")
private String eventId;
@ApiModelProperty(value = "任务运行开始时间")
private Long createDateNum;
@ApiModelProperty(value = "处理信息")
private String dealInfo;
}
@FeignClient(name = "cpe-etl-svc",contextId = "etlBackend")
@Api(tags = "ETL数据处理中心管理台接口")
@RequestMapping("/cpe-etl-backend")
public interface EtlFeignBackend {
@PostMapping(EtlFuncIds.backend.RUN_ONE_TASK)
@ApiOperation(value = "数据中心-管理台启动单任务", notes = "",
httpMethod = "POST", responseContainer = "error_no=0 正常")
Result<EventDto> runOneTask(@RequestBody ExecExternalServiceTaskParam param);
}
翻页出参
@FeignClient(name = "cpe-etl-svc",contextId = "etlBackend")
@Api(tags = "ETL数据处理中心管理台接口")
@RequestMapping("/cpe-etl-backend")
public interface EtlFeignBackend {
@PostMapping(EtlFuncIds.backend.QUERY_EVENT)
@ApiOperation(value = "数据中心-管理台事件查询",notes = "",
httpMethod = "POST", responseContainer = "error_no=0 正常")
Result<PageInfoDto<EventDto>> queryTask(@RequestBody QueryEventParam param);
}
- 异常
请使用:
public class EtleventServiceImpl implements EtleventService {
@Override
public Etlevent getEtlevent(String eventId) {
Etlevent event = etleventDao.selectById(eventId);
if (null == event) {
throw new BaseErrInfoException(EtlErrorNo.ERROR_10070015, "此事件!");
}
return event;
}
}
定义自己业务的错误号,请使用自己申请的号段。
public interface XXXErrorNo extends BasicErrorCodes {
/** 不存在{1}! */
public final static String ERROR_10070015="10070015";
}
在你项目的resources/message/error-desc.properties中定义内部错误号对应错误信息:
#业务
errorInfo.10070015=不存在%1s!
在你项目的resources/message/error-convert.properties中可以把外部错误号对应到内部错误号
errorConvert.out1111=10070019
一般我们写业务代码时,只用考虑正常和业务异常两种情况。
如果有像sql、connection等等系统级异常会被异常切面捕获,自动包装成Result{error_no=1001}
1001错误号对应的error_info在error-desc.properties:
#errorInfo.1001=执行错误 #要把真正的错误内容显示出来,就注释这一行
把这一行注释掉,就可以看到真正的异常了。
但是在客户端的客户是不想看这些的。
所以在消费者层我们不能注释这一行。
- 返回结果集
@RestController
public class EtlFeignBackendController implements EtlFeignBackend {
@Override
@Trace
@Tag(key = "outputparam", value = "returnedObj")
@Tag(key = "inputparam", value = "arg[0]")
public Result<EventDto> runOneTask(ExecExternalServiceTaskParam param) {
Result ret = ResultUtil.genSuccessResult();
EventDto dto = runTaskService.runExternaltask(param);
ret.setData(dto);
return ret;
}
@Override
@Trace
@Tag(key = "outputparam", value = "returnedObj")
@Tag(key = "inputparam", value = "arg[0]")
public Result<PageInfoDto<EventDto>> queryTask(QueryEventParam param) {
Result ret = ResultUtil.genSuccessResult();
PageInfoDto<EventDto> list = etleventService.queryEvent(param);
ret.setData(list);
return ret;
}
}
这里用到了skywalking注解:@Trace、@Tag,用于记录出入参数。
之后的微服务,都将依赖于这个工程的jar包。