Show me code
记录各种功能的实现方式
Java
1、工具类私有化构造方法
private StringUtils() {
throw new IllegalStateException("Utility class");
}
2、获取前一个月的时间节点
// 输出的结果不正确
new Date(currentTimeMillis - 30 * 24 * 60 * 60 * 1000);
问题原因: 30 * 24 * 60 * 60 * 1000 的值已经超过了 int 的最大值,导致计算结果不正确。
解决方案: 只需要在 1000 加上 L 即可. new Date(currentTimeMillis - 30 * 24 * 60 * 60 * 1000L);
3、Collectors.map() 报错
问题原因: map 中的 value 不允许为空.
解决方法: 使用 map 的重载方法.
Map<String, String> map = list.stream()
.collect(HashMap::new,(m,v)-> m.put(v.getId(),v.getName()),HashMap::putAll);
4、根据某个字段 join 成一个字符串
String orgIds = orgList.stream().map(SysBasicOrgDto::getId)
.collect(Collectors.joining(","));
5、Map 用法
1、compute
compute() 方法对 hashMap 中指定 key 的值进行重新计算。如果 key 不存在,会将 key 和 value 存入 hashMap 中。
使用 compute 方法可以简化代码
if (dayMountMap.containsKey(day)) {
MutablePair<Integer, Integer> pair = dayMountMap.get(day);
if (isCompleted) {
pair.setLeft(pair.getLeft() + trend.getAmount());
pair.setRight(pair.getRight() + trend.getAmount());
} else {
pair.setRight(pair.getRight() + trend.getAmount());
}
} else {
dayMountMap.put(day, MutablePair.of(isCompleted ? trend.getAmount() : 0,
trend.getAmount()));
}
简化后
dayMountMap.compute(day,(key,pair)->{
if(pair == null){
pair = MutablePair.of(0,0);
}
int completedIncrement = isCompleted ? trend.getAmount() : 0;
pair.setLeft(pair.getLeft() + completedIncrement);
pair.setRight(pair.getRight() + trend.getAmount());
return pair;
});
6、保留指定位小数
RoundingMode.HALF_UP 四舍五入
double d = 12.3456;
BigDecimal b = new BigDecimal(d);
d = b.setScale(1, RoundingMode.HALF_UP).doubleValue();
System.out.println(d);
MyBatis-Plus
1、新增
baseMapper.insert(org);
2、删除
int delete = historyRecordMapper.deleteById(id);
3、修改
UpdateWrapper<SysOrg> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", orgId)
.set("udate", new Date())
.set("uoperator", String.valueOf(request.getAttribute(JwtUtil.JWT_USERID)))
.set("delete_status", OrmConstant.DELETE_STATUS_DELETE);
baseMapper.update(null, updateWrapper);
4、查询
简单查询
QueryWrapper<SysOrg> existQueryWrapper = new QueryWrapper<SysOrg>()
.eq("name", org.getName())
.eq("parent_id", org.getParentId());
SysOrg sysOrg = baseMapper.selectOne(existQueryWrapper);
复杂查询1
SELECT * FROM user WHERE status = 1 AND (name = 'John' OR name = 'Doe') ORDER BY create_time DESC
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
.eq("status", 1) // WHERE status = 1
.and(i -> i.eq("name", "John").or().eq("name", "Doe")) // AND (name = 'John' OR name = 'Doe')
.orderByDesc("create_time"); // ORDER BY create_time DESC
复杂查询2
SELECT COUNT( * ) FROM point_param WHERE ((param_type <> ? AND addr IN (?)) OR (param_type = ? AND addr = ? AND bit = ?))
QueryWrapper<PointParam> query = new QueryWrapper<>();
query.or(wrapper -> wrapper.ne("param_type", "0302")
.in("addr", list.stream().map(PointParamVO::getAddr).collect(Collectors.toList())));
list.stream().filter(vo -> "0302".equals(vo.getParamType())).forEach(vo -> {
query.or(wrapper -> wrapper.eq("param_type", "0302")
.eq("addr", vo.getAddr())
.eq("bit", vo.getBit())
);
});
5、查询总条数
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
String userName = vo.getUserName();
String userCode = vo.getUserCode();
String email = vo.getEmail();
String mobile = vo.getMobile();
if (StringUtils.isNotEmpty(userName)) {
queryWrapper.or().eq("user_name", userName);
}
if (StringUtils.isNotEmpty(userCode)) {
queryWrapper.or().eq("user_code", userCode);
}
if (StringUtils.isNotEmpty(email)) {
queryWrapper.or().eq("email", email);
}
if (StringUtils.isNotEmpty(mobile)) {
queryWrapper.or().eq("mobile", mobile);
}
Integer count = this.baseMapper.selectCount(queryWrapper);
6、自动填充字段
https://baomidou.com/guides/auto-fill-field/
需要实现一个 MetaObjectHandler 接口,并将这个实现类交由 Spring 容器管理。
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始插入填充...");
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("开始更新填充...");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
需要在实体类的字段中加上 @TableField 注解,并设置 fill 属性
public class User {
@TableField(fill = FieldFill.INSERT)
private String createTime;
@TableField(fill = FieldFill.UPDATE)
private String updateTime;
// 其他字段...
}
7、分页
EasyExcel
1、导出 Excel
前台发送 HTTP 请求
curl --location 'http://localhost:8888/api/historyRecord/export-history-record' `
--header 'Access-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiMSIsImxvY2tUaW1lIjo1OTk5NDAsInRva2VuVHlwZSI6IjAiLCJ1c2VyTmFtZSI6ImFkbWluIiwiZXhwIjoxNzE3NjY1MzczLCJ1c2VySUQiOiJhZG1pbiIsImlhdCI6MTcxNzA2MDU3M30.YOJVnPi9JuUuKbj1t-wBT1fXGiEYxTRMJlWUFb02_0c' `
--header 'Content-Type: application/json' `
--data '{
"pointId":"2593",
"startTime": "2024-05-30 17:42:00",
"endTime": "2024-05-30 17:43:00",
"headList": [
"值",
"时间"
],
"headKeyList": [
"dataValue",
"occrentDate"
]
}'
Controller 接收请求
@ApiOperation(value = "导出历史数据")
@PostMapping(value = "/exportXxxx")
public void exportXxxx(@RequestBody XxxxVo xxxVo, HttpServletResponse resp)throws Exception {
xxxxService.exportXxxx(xxxVo , resp) ;
}
Service 实现导出的功能
@Override
public void exportHistoryData(HistoryRecordQueryExportVo queryExportVo, HttpServletResponse response) throws Exception {
// head列表
List<List<String>> excelHead = new ArrayList<>();
List<String> headList = queryExportVo.getHeadList();
headList.forEach(headStr -> {
List<String> temp = new ArrayList<>();
temp.add(headStr);
excelHead.add(temp);
});
String filename = "历史数据导出-";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String startDateStr = queryExportVo.getStartTime().format(dateTimeFormatter);
String endDateStr = queryExportVo.getEndTime().format(dateTimeFormatter);
if (startDateStr.equals(endDateStr)) {
filename += startDateStr;
} else {
filename += startDateStr + "-" + endDateStr;
}
// 设置文本内省
response.setContentType("application/octet-stream");
// 设置字符编码
response.setCharacterEncoding("utf-8");
// 设置响应头
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8") + ".xlsx");
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), HistoryRecordDTO.class)
// 字段列表
.includeColumnFiledNames(queryExportVo.getHeadKeyList())
.build();
WriteSheet writeSheet = EasyExcel.writerSheet(0, "sheet0").registerWriteHandler(new HistoryRecordExcelStyleHandler()).build();
writeSheet.setHead(excelHead);
HistoryRecordQuery query = new HistoryRecordQuery();
query.setStartTime(queryExportVo.getStartTime());
query.setEndTime(queryExportVo.getEndTime());
ListParam listParam = new ListParam();
listParam.setPointId(queryExportVo.getPointId());
listParam.setStartTime(queryExportVo.getStartTime());
listParam.setEndTime(queryExportVo.getEndTime());
List<HistoryRecordDTO> list = baseMapper.selectListByDate(listParam);
excelWriter.write(list, writeSheet);
excelWriter.finish();
}
EasyExcel 样式处理器
public class HistoryRecordExcelStyleHandler extends AbstractCellStyleStrategy {
protected CellStyle headCellStyle;
protected WriteCellStyle headWriteCellStyle;
protected WriteCellStyle contentWriteCellStyle;
protected CellStyle contentCellStyle;
protected Sheet sheet;
/**
* 记录此字符是否出现,如果第一次出现,则设置宽度,否则不设置,避免合并列时太宽
*/
private Set<String> isFirst = new HashSet<>();
/**
* 默认高度
*/
protected static final int DEFAULT_HEIGHT = 300;
private static final int MAX_WIDTH = 255;
@Override
protected void initCellStyle(Workbook workbook) {
headWriteCellStyle = new WriteCellStyle();
WriteFont headWriteFont = new WriteFont();
headWriteCellStyle.setWriteFont(headWriteFont);
headCellStyle = StyleUtil.buildHeadCellStyle(workbook, headWriteCellStyle);
contentWriteCellStyle = new WriteCellStyle();
contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
contentWriteCellStyle.setWrapped(true);
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
contentCellStyle = StyleUtil.buildContentCellStyle(workbook, contentWriteCellStyle);
contentCellStyle.setAlignment(HorizontalAlignment.CENTER);
contentCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
sheet = workbook.getSheet("sheet0");
}
@Override
protected void setHeadCellStyle(Cell cell, Head head, Integer relativeRowIndex) {
cell.setCellStyle(headCellStyle);
cell.getRow().setHeight((short) (2 * DEFAULT_HEIGHT));
int columnWidth = cell.getStringCellValue().getBytes().length;
if (columnWidth > MAX_WIDTH) {
columnWidth = MAX_WIDTH;
}
if (!isFirst.contains(cell.getStringCellValue())) {
//统一加3的宽度,显得不紧凑
sheet.setColumnWidth(cell.getColumnIndex(), (columnWidth + 6) * 256);
isFirst.add(cell.getStringCellValue());
}
if ("时间".equals(cell.getStringCellValue())) {
sheet.setColumnWidth(cell.getColumnIndex(), (columnWidth + 25) * 256);
}
}
@Override
protected void setContentCellStyle(Cell cell, Head head, Integer relativeRowIndex) {
cell.setCellStyle(contentCellStyle);
cell.getRow().setHeight((short) (2 * DEFAULT_HEIGHT));
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
Head head, Integer relativeRowIndex, Boolean isHead) {
// 非 head 时,给 cell 设置样式
if (!isHead) {
setContentCellStyle(cell, head, relativeRowIndex);
}
}
}
MyBatis Plus 查询数据
数据库为 Sqlite3
<select id="selectListByDate" resultMap="HistoryRecordMap">
SELECT
id , point_id , data_value ,
strftime( '%Y-%m-%d %H:%M:%S ' ,occrent_date) as occrent_date
FROM
history_record
WHERE
point_id = #{listParam.pointId}
and occrent_date between #{listParam.startTime} and #{listParam.endTime}
order by occrent_date desc
</select>
实体类
数据库表字段
@Data
@ApiModel
public class HistoryRecordDTO {
private Integer id;
private Integer pointId;
private BigDecimal dataValue;
@DateTimeFormat(pattern = DATE_TIME_WITH_LINE)
@JsonFormat(pattern = DATE_TIME_WITH_LINE, timezone = "GMT+8")
private String occrentDate;
}
查询参数
@Data
@ApiModel
public class ListParam {
@ApiModelProperty("测点id")
private String pointId;
@ApiModelProperty("开始时间")
@DateTimeFormat(pattern = DATE_TIME_WITH_LINE)
@JsonFormat(pattern = DATE_TIME_WITH_LINE, timezone = "GMT+8")
private LocalDateTime startTime;
@ApiModelProperty("结束时间")
@DateTimeFormat(pattern = DATE_TIME_WITH_LINE)
@JsonFormat(pattern = DATE_TIME_WITH_LINE, timezone = "GMT+8")
private LocalDateTime endTime;
}
在导出时,只导出部分字段
使用 includeColumnFiledNames 方法,将需要导出的字段的名称传入。
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), HistoryRecordDTO.class)
// 字段列表
.includeColumnFiledNames(queryExportVo.getHeadKeyList())
.build();
设置表头样式
实现 AbstractCellStyleStrategy 类
WriteSheet writeSheet = EasyExcel.writerSheet(0, "sheet0")
// 自定义样式
.registerWriteHandler(new HistoryRecordExcelStyleHandler())
.build();
2、导入 Excel
实现 ReadListener 接口
@Slf4j
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class SysUserExcelReadListener implements ReadListener<SysUserExcelData> {
@Autowired
private SysUserServiceImpl sysUserService;
@Autowired
private ISysRoleService roleService;
/**
* 数据
*/
@Getter
private List<SysUserExcelData> datas = new ArrayList<>();
@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
throw exception;
}
/**
* 每一行数据解析都会来调用
* @param data
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
* analysis context
*/
@Override
public void invoke(SysUserExcelData data, AnalysisContext context) {
validateUserCode(data);
String roleName = data.getMainRole();
String roleId = roleService.getRoleIdByName(roleName);
if (StringUtils.isEmpty(roleId)) {
throw new InheExceptionBase(500, "角色" + roleName + "不存在!");
}
data.setMainRole(roleId);
datas.add(data);
}
/**
* 读取完所有数据后的操作
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
List<InsertSysUserVo> list = SysUserConvert.INSTANCE.toInsVoList(datas);
sysUserService.batchInsertOrUpdate(list);
}
@Override
public boolean hasNext(AnalysisContext context) {
return true;
}
@Override
public void invokeHead(Map headMap, AnalysisContext context) {
}
/**
* 校验用户信息
* @param data 用户信息
*/
private void validateUserCode(SysUserExcelData data) {
String userName = data.getUserName();
if (StringUtils.isEmpty(userName)) {
throw new InheExceptionBase(-10000, "用户名称不允许为空!");
}
String userCode = data.getUserCode();
if (StringUtils.isEmpty(userCode)) {
throw new InheExceptionBase(-10000, "用户编码不允许为空!");
}
String mainRole = data.getMainRole();
if (StringUtils.isEmpty(mainRole)) {
throw new InheExceptionBase(-10000, "主角色不允许为空!");
}
String department = data.getDepartment();
if (StringUtils.isEmpty(department)) {
throw new InheExceptionBase(-10000, "部门不允许为空!");
}
String position = data.getPosition();
if (StringUtils.isEmpty(position)) {
throw new InheExceptionBase(-10000, "职位不允许为空!");
}
String mobile = data.getMobile();
if (StringUtils.isEmpty(mobile)) {
throw new InheExceptionBase(-10000, "手机号不允许为空!");
}
String email = data.getEmail();
if (StringUtils.isEmpty(email)) {
throw new InheExceptionBase(-10000, "邮箱不允许为空!");
}
}
}
导入的方法
@Service
public class ExcelSysUserServiceImpl implements IExcelSysUserService {
@Autowired
private ApplicationContext context;
public SysUserExcelReadListener getSysUserExcelReadListener() {
return context.getBean(SysUserExcelReadListener.class);
}
@Override
public R importSysUserExcel(MultipartFile multipartFile) throws IOException {
SysUserExcelReadListener readListener = getSysUserExcelReadListener();
EasyExcelFactory.read(multipartFile.getInputStream(), SysUserExcelData.class, readListener)
.sheet(0) //指定读取第一个工作表
.headRowNumber(1) //指定标题行在第一行
.doRead();
return R.ok(true,"导入成功!");
}
}
每行数据对象
@Data
public class SysUserExcelData {
@ExcelProperty(value = "User Code", index = 0)
private String userCode;
@ExcelProperty(value = "User Name", index = 1)
private String userName;
@ExcelProperty(value = "Main Role", index = 2)
private String mainRole;
@ExcelProperty(value = "Position", index = 3)
private String position;
@ExcelProperty(value = "E-mail", index = 4)
private String email;
@ExcelProperty(value = "Phone Number", index = 5)
private String mobile;
@ExcelProperty(value = "Department", index = 6)
private String department;
@ExcelProperty(value = "Description", index = 7)
private String description;
}
Spring
1、获取 application.yml 中的配置的参数
通过 @Value("aaa.bbb")