2023.056.07和09培训
项目实战
目录
一、infracore(基础核心层)
1.1database
1.2config
1.3util
二、业务领域模块
2.1structure模块
2.1.1domain层
2.1.2application层
2.1.3adapter层
2.2sensor模块
2.2.1domian层
2.2.2application层
2.2.3adapter层
一、infracore(基础核心层)
编写整个项目中全部通用的部分,包括:数据库操作、配置类、工具类(随机数、随机ID生成器、格式校验器)、缓存配置......
1.1database
Mysql包:
具体模块包(一个数据表对应一个模块)
DO数据容器(与数据表一一对应)
Mapper(Mybatis或plus操作数据库的SQL)
MapperEnum(字段枚举类)
MapperHelper(面向数据库层面的缓存服务类)
1.2config
1.3util
@Slf4j
public class SnowFlakeUtil {
/**
* 派号器workid:0~31
* 机房datacenterid:0~31
*/
private static Snowflake snowflake = IdUtil.createSnowflake(1, 1);
public static Long nextId() {
return snowflake.nextId();
}
}
二、业务领域模块
2.1structure模块
一个业务领域一个包
structure模块下的结构:
2.1.1domain层
domain领域层:
结构物基础信息 + 系统工程管理结点信息 + 文档信息 + 安全信息 + 统计信息
把零碎的、分散的基础信息,组建成完整的专业领域
reader
做所有的数据库读操作,组织各个数据表的数据结构,封装成专业名词,参数校验、分页、数据封装、无效数据剔除......
专业名词封装
//专业名词
@Data
public class Structure {
private String id; // 唯一标识
private String code; // 桥梁自定义编码-用于外连接-连接到工程结构树节点中的结构物节点上
private String structureCode; // 结构物编码-数据对接专用-TDengine超级表名需要
private String structureName; // 结构物名称
private double longitude; // 经度
private double latitude; // 纬度
private String structureType; // 结构物类型-根据数据字典:桥梁、隧道、边坡、涵洞...
private String address; // 结构物准确地址描述
private long sensorCount;
public static Structure generateStructure(StructureDO structureDO,long sensorCount){
Structure structure = new Structure();
BeanUtils.copyProperties(structureDO, structure);
structure.setSensorCount(sensorCount);
return structure;
}
}
reader编写对应方法
/**
* @author: yangkx
* @Title: SensorReader
* @ProjectName: SwjtuPeixun
* @Description:
* @date: 2023-06-11 10:14
*/
@Component
public class SensorReader {
@Autowired
private SensorMapper sensorMapper;
@Autowired
private MonitorSchemeMapper monitorSchemeMapper;
//获取一座桥下面的所有传感器
public List<Sensor> getAllForStructure(String structureNodeCode){
LambdaQueryWrapper<SensorDO> lqw = new LambdaQueryWrapper<>();
lqw.eq(SensorDO::getCode, structureNodeCode);
List<SensorDO> records = sensorMapper.selectList(lqw);
List<Sensor> result = new ArrayList<>();
for(SensorDO record : records){
String monitorSchemeId = record.getMonitorSchemeId();
MonitorSchemeDO monitorScheme = monitorSchemeMapper.getById(monitorSchemeId);
//专业名词
Sensor sensor = Sensor.generateSensor(record, monitorScheme);
//System.out.println(" " + sensor);
//System.out.println(record);
result.add(sensor);
}
return result;
}
}
writer
做所有的增删改操作
1)在reader包里,添加StructureCreateEntity类
添加转化为DO类的方法
@Data
public class StructureCreateEntity {
private String code; // 桥梁自定义编码-用于外连接-连接到工程结构树节点中的结构物节点上
private String structureCode; // 结构物编码-数据对接专用-TDengine超级表名需要
private String structureName; // 结构物名称
private String type; // 结构物类型-例如大桥,中桥,小桥
private String level; // 结构物级别-例如2类,1类
private double longitude; // 经度
private double latitude; // 纬度
private StructureType structureType; // 结构物类型-根据数据字典:桥梁、隧道、边坡、涵洞...
//private String structureImage; // 结构物图片路径
private String fileId; // Bimface模型文件ID
private String address; // 结构物准确地址描述
private String structureStyle; // 结构形式,如:150m钢筋混凝土箱型肋拱
private String beginYear; // 结构物开始服役年份
private String endYear; // 结构物结束服役年份(若有预期的,可填,没有则不填)
private String structureDescribe; // 结构物描述
private double bimLatitude; // BIM三维地图坐标经度
private double bimLongitude; // BIM三维地图坐标纬度
private double bimRotation; // BIM三维地图坐标旋转角度系数
private double bimHigh; // BIM三维地图坐标高度
public StructureDO toStructureDO(){
StructureDO structureDO = new StructureDO();
BeanUtils.copyProperties(this, structureDO);
return structureDO;
}
}
2) 回到database包里,在structure里新建StructureType类
public enum StructureType {
BRIDGE("桥梁"),TUNNEL("隧道"),CULVERT("涵洞");
private final String value;
StructureType(String value){
this.value = value;
}
public String value(){return value;}
public static StructureType parseType(String type) throws Exception{
switch (type){
case "桥梁":
return StructureType.BRIDGE;
case "隧道":
return StructureType.TUNNEL;
case "涵洞":
return StructureType.CULVERT;
default:
throw new Exception("工程结构结点类型解析失败");
}
}
}
3)修改StructureService 添加create方法
public void create(CreateInDTO param) throws Exception{
structureWriter.create(param.toEntity());
}
4)为writer添加相应方法
@Component
public class StructureWriter {
@Autowired
private StructureMapper structureMapper;
public boolean create(StructureCreateEntity entity) throws Exception {
int insertResult = structureMapper.insert(entity.toStructureDO());
if(insertResult != 1)
throw new Exception("插入失败!");
return true;
}
public boolean uploadImage(String structureNodeCode,String url) throws Exception {
int var = structureMapper.uploadImageUrl(structureNodeCode, url);
if(var != 1)
throw new Exception("插入失败!");
return true;
}
}
5)修改applivation层里的StructureService
添加方法
public boolean create(CreateInDTO param) throws Exception{
boolean var = structureWriter.create(param.toEntity());
return var;
}
public boolean uploadImage(String structureNodeCode, MultipartFile file) throws Exception{
//1.判断文件有效
if(file == null)
throw new Exception("上传的文件异常");
//2.先判断这个结构物存不存在
if(structureNodeCode == null || "".equals(structureNodeCode))
throw new Exception("输入结构物为空");
Structure structure = structureReader.getByNodeCode(structureNodeCode);
if(structure == null)
throw new Exception("结构物不存在");
//3.file上传到文件服务器
String url = fileToHost(file);
if(url == null || "".equals(url))
throw new Exception("文件上传失败");
boolean flag = structureWriter.uploadImage(structureNodeCode, url);
return flag;
}
private String fileToHost(MultipartFile file){
System.out.println("文件正在上传到服务器");
StringBuilder builder = new StringBuilder();
builder.append("image").append(Math.random() * 1000000).append(".png");
return builder.toString();
}
6)转到adapter里 修改controller 进行测试
2.1.2application层
应用服务层: 编写具体的业务逻辑
event:领域时间驱动,发布器和处理器
DTO:Data Transfer Object
service:具体执行的业务逻辑,不关心数据,只管用
StructureService:structure的业务操作
@Service
public class StructureService {
@Autowired
private StructureReader structureReader;
public StructureOutDTO getByNodeCode(QueryParamInDTO param) throws Exception {
if(!param.isValid())
return null;
Structure structure = structureReader.getByNodeCode(param.getStructureNodeCode());
System.out.println(" " + structure);
System.out.println("原始经纬度:" + structure.getLatitude() + " " + structure.getLongitude());
//开始经纬度偏离业务 模拟
switch(param.getIdentify()){
case "超级管理员":
System.out.println("超级管理员 经纬度:" + structure.getLatitude() + " " + structure.getLongitude());
break;
case "普通管理员":
double random = Math.random();
double rate = (random - 0.5) / (double)100;
structure.setLatitude(structure.getLatitude() * (1D + rate));
structure.setLongitude(structure.getLongitude() * (1D + rate));
System.out.println("普通管理员 经纬度:" + structure.getLatitude() + " " + structure.getLongitude());
break;
case "用户":
double random2 = Math.random();
double rate2 = ((random2 - 0.5) / (double)100) * 2;
structure.setLatitude(structure.getLatitude() * (1D + rate2));
structure.setLongitude(structure.getLongitude() * (1D + rate2));
System.out.println("用户 经纬度:" + structure.getLatitude() + " " + structure.getLongitude());
break;
default:
break;
}
StructureOutDTO structureOutDTO = StructureOutDTO.generate(structure, param.getIdentify());
return structureOutDTO;
}
}
QueryParamInDTO:封装查询参数
@Data
public class QueryParamInDTO {
private String structureNodeCode;
private String identify="用户";
public QueryParamInDTO(String structureNodeCode, String identify) {
this.structureNodeCode = structureNodeCode;
this.identify = identify;
}
public QueryParamInDTO() {
}
public boolean isValid(){
if(structureNodeCode == null || "".equals(structureNodeCode))
return false;
if(identify == null || "".equals(identify))
return false;
return true;
}
}
StructureOutDTO:封装数据 再次添加额外数据
@Data
public class StructureOutDTO {
private String id; // 唯一标识
private String code; // 桥梁自定义编码-用于外连接-连接到工程结构树节点中的结构物节点上
private String structureCode; // 结构物编码-数据对接专用-TDengine超级表名需要
private String structureName; // 结构物名称
private double longitude; // 经度
private double latitude; // 纬度
private String structureType; // 结构物类型-根据数据字典:桥梁、隧道、边坡、涵洞...
private String address; // 结构物准确地址描述
//额外信息
private long sensorCount;
//再加额外数据
private Date queryTime;
private String userIdentify;
public static StructureOutDTO generate(Structure structure,String identify){
StructureOutDTO structureOutDTO = new StructureOutDTO();
BeanUtils.copyProperties(structure, structureOutDTO);
structureOutDTO.setUserIdentify(identify);
structureOutDTO.setQueryTime(new Date(System.currentTimeMillis()));
return structureOutDTO;
}
}
CreateInDTO:获取数据封装转化为Entity
@Data
public class CreateInDTO {
private String code; // 桥梁自定义编码-用于外连接-连接到工程结构树节点中的结构物节点上
private String structureCode; // 结构物编码-数据对接专用-TDengine超级表名需要
private String structureName; // 结构物名称
private String type; // 结构物类型-例如大桥,中桥,小桥
private String level; // 结构物级别-例如2类,1类
private double longitude; // 经度
private double latitude; // 纬度
//字符串 ---> enum
private String structureType; // 结构物类型-根据数据字典:桥梁、隧道、边坡、涵洞...
//private String structureImage; // 结构物图片路径
private String fileId; // Bimface模型文件ID
private String address; // 结构物准确地址描述
private String structureStyle; // 结构形式,如:150m钢筋混凝土箱型肋拱
private String beginYear; // 结构物开始服役年份
private String endYear; // 结构物结束服役年份(若有预期的,可填,没有则不填)
private String structureDescribe; // 结构物描述
private double bimLatitude; // BIM三维地图坐标经度
private double bimLongitude; // BIM三维地图坐标纬度
private double bimRotation; // BIM三维地图坐标旋转角度系数
private double bimHigh; // BIM三维地图坐标高度
public StructureCreateEntity toEntity() throws Exception{
StructureCreateEntity structureCreateEntity = new StructureCreateEntity();
BeanUtils.copyProperties(this, structureCreateEntity);
StructureType structureType = StructureType.parseType(this.structureType);
if(structureType != null)
structureCreateEntity.setStructureType(structureType);
return structureCreateEntity;
}
}
2.1.3adapter层
适配器:适配客户、第三方需求
VO:
controller:接口开放
anticorrosive:防腐层 用于保证这个领域application层的纯洁性
test1:
编写Controller 在网页进行测试
@RestController
@RequestMapping("/structure")
public class StructureController {
@Autowired
private StructureService structureService;
@GetMapping("/query/{structureNodeCode}")
public StructureOutDTO query(@PathVariable(value = "structureNodeCode") String structureNodeCode) throws Exception {
QueryParamInDTO param = new QueryParamInDTO();
param.setStructureNodeCode(structureNodeCode);
StructureOutDTO outDTO = structureService.getByNodeCode(param);
return outDTO;
}
}
测试结果:
test2:
修改StructureContorller
测试图片插入
@PostMapping("/create")
public boolean create(@RequestBody CreateInDTO param) throws Exception{
structureService.create(param);
return true;
}
@GetMapping("/uploadImage/{structureNodeCode}")
public boolean uploadImage(@PathVariable("structureNodeCode") String structureNodeCode) throws Exception{
boolean b = structureService.uploadImage(structureNodeCode,null);
return b;
}
测试结果
2.2sensor模块
模块结构同structure模块,下面的模块结构也一样,就不再细说了
2.2.1domian层
domain领域层:
结构物基础信息 + 系统工程管理结点信息 + 文档信息 + 安全信息 + 统计信息
把零碎的、分散的基础信息,组建成完整的专业领域
task1:返回封装好的sensor
在reader包下新建entity包,新建Sensor类
Sensor类 = sensorDO + monitorSchemeDO
在Sensor类里添加generateSensor静态方法,返回封装好的Sensor对象
/**
* @author: yangkx
* @Title: Sensor
* @ProjectName: SwjtuPeixun
* @Description:
* @date: 2023-06-11 10:45
*/
//专业名词类
@Data
public class Sensor {
private String id = SnowFlakeUtil.nextId().toString();
private String sensorId; // 内部使用的,数据对接用的 id
//private String monitorSchemeId; // 监测方案 id,与数据字典 - 监测方案挂钩
private String monitorSchemeId; //监测方案 唯一 id
private String monitorTypeName; // 监测类型名
private String monitorContentName; // 监测内容名
private String type; // 一级分类,结构响应、作用...
private String location; // 位置
private String sensorInstallCode; // 设备安装代码,一般是按规范指定的传感器id
private String componentId; // BIM模型上的组件id
private String sensorType; // 传感器类型,如倾角计
private String sensorName; // 传感器名字,有需要再使用
private String remark; // 备注
public static Sensor generateSensor(SensorDO sensorDO, MonitorSchemeDO monitorSchemeDO){
//sensorDO的数据
Sensor sensor = new Sensor();
sensor.setId(sensorDO.getId());
sensor.setSensorId(sensorDO.getSensorId());
sensor.setLocation(sensorDO.getLocation());
sensor.setSensorInstallCode(sensorDO.getSensorInstallCode());
sensor.setComponentId(sensorDO.getComponentId());
sensor.setSensorType(sensorDO.getSensorType());
sensor.setSensorName(sensorDO.getSensorName());
sensor.setRemark(sensorDO.getRemark());
//monitorSchemeDO的数据
sensor.setMonitorSchemeId(monitorSchemeDO.getId());
sensor.setMonitorTypeName(monitorSchemeDO.getMonitorTypeName());
sensor.setMonitorContentName(monitorSchemeDO.getMonitorContentName());
sensor.setType(monitorSchemeDO.getType());
//返回封装好的对象
return sensor;
}
}
测试专业名词
1)Reader里编写对应方法
@Component
public class SensorReader {
@Autowired
private SensorMapper sensorMapper;
@Autowired
private MonitorSchemeMapper monitorSchemeMapper;
//获取一座桥下面的所有传感器
public List<Sensor> getAllForStructure(String structureNodeCode){
LambdaQueryWrapper<SensorDO> lqw = new LambdaQueryWrapper<>();
lqw.eq(SensorDO::getCode, structureNodeCode);
List<SensorDO> records = sensorMapper.selectList(lqw);
List<Sensor> result = new ArrayList<>();
for(SensorDO record : records){
String monitorSchemeId = record.getMonitorSchemeId();
MonitorSchemeDO monitorScheme = monitorSchemeMapper.getById(monitorSchemeId);
//专业名词
Sensor sensor = Sensor.generateSensor(record, monitorScheme);
//System.out.println(" " + sensor);
//System.out.println(record);
result.add(sensor);
}
return result;
}
}
2)test类调用reader里的方法
@Component
public class TestClass {
@Autowired
private StructureReader structureReader;
@Autowired
private SensorReader sensorReader;
@PostConstruct
private void init(){
//structureReader.getAll();
sensorReader.getAllForStructure("1609494584646307840");
}
}
3)运行结果
2.2.2application层
应用服务层: 编写具体的业务逻辑
event:领域时间驱动,发布器和处理器
DTO:Data Transfer Object
service:具体执行的业务逻辑,不关心数据,只管用
@Service
public class SensorService {
@Autowired
private SensorReader sensorReader;
public void getForStructure(String structureNodeCode){
List<Sensor> records = sensorReader.getAllForStructure(structureNodeCode);
return;
}
}
2.2.3adapter层
适配器:适配客户、第三方需求
VO:
controller:接口开放
anticorrosive:防腐层 用于保证这个领域application层的纯洁性