【Java】单号创建服务
需求:ERP项目存在若干个业务功能,每个业务的单子的单号创建规则需要被统一规划
1、每个业务有自己对应的标识
2、业务单号必须以英文字母为前缀,长度在2 - 4个字符
3、单号的组成 = [ 前缀 ] + [ 日期单位(8) ] + [ 当前序列 ]
4、日期单位可以灵活设置,按年,月,日为单位,即中间的8位精确到什么日期单位
5、结尾对【当前序列】自增后进行补位填充,拼接后就是新的单号
设计的表结构:
1、业务标识 + 前缀 + 日期单位(年,月,日) 组合为唯一键
2、表的维护全靠建单逻辑执行(只有新增和更新操作)
CREATE TABLE `sys_co_servcode` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '系统编码 主键,初始值为“100001”',
`sc_serv_ident` varchar(32) NOT NULL COMMENT '业务标识 参见业务标识对照表<类:ServiceIdentEnum>',
`sc_prifix` varchar(4) NOT NULL COMMENT '编码前缀 默认用两位,最长四位;',
`sc_year` char(4) NOT NULL COMMENT '所属年',
`sc_month` char(2) NOT NULL COMMENT '所属月',
`sc_day` char(2) NOT NULL COMMENT '所属日',
`sc_num` int(11) NOT NULL COMMENT '当前编号',
`create_time` datetime NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100012 DEFAULT CHARSET=utf8 COMMENT='业务编码表';
设计的接口服务:
1、接口设定了单号长度设置,需要校验单号长度是否不足
2、日期根据字段信息,需要自己计算年月日,所以这里弄成枚举类型作为入参
package cn.hyite.amerp.system.common.servcode.service; import cn.hyite.amerp.system.common.servcode.dto.DateUnit; /**
* sys_co_servcode 业务编码表 服务类
*
* @author OnCloud9
* @version 1.0
* @project server
* @date 2022-12-15
*/
public interface ISysCoServcodeService { /**
* 根据 [业务标识] + [前缀定义] + [日期精度] + [单号总长度] 创建最新的单号
* @param servIdent 业务标识
* @param codePrefix 编号前缀定义(2 ~ 4)字符长度
* @param dateUnit 日期单位 [year, month, day]
* @param length 单号总长度
* @return String 最新业务编号
* @author OnCloud9
* @date 2022/12/15 14:08
*
*/
String createServiceCode(String servIdent, String codePrefix, DateUnit dateUnit, Integer length);
}
考虑到单号可变长度,每个日期枚举对应设置了长度限制,方便接口实现做长度计算校验
package cn.hyite.amerp.system.common.servcode.dto; import lombok.Getter; /**
* 日期单位枚举类
*
* @author OnCloud9
* @version 1.0
* @project server
* @date 2022年12月15日 14:36
*/
@Getter
public enum DateUnit {
YEAR(4),
MONTH(6),
DAY(8)
;
public static final int TOTAL_LENGTH = 8;
private final int length;
DateUnit(int length) {
this.length = length;
}
}
接口实现:
1、一个新的业务建单规则没有使用时,调用后记录规则,返回单号
2、再次调用时,根据记录获取最新单号,更新记录的单号后,返回单号
package cn.hyite.amerp.system.common.servcode.service.impl; import cn.hyite.amerp.common.ResultMessage;
import cn.hyite.amerp.common.service.BaseService;
import cn.hyite.amerp.common.util.Assert;
import cn.hyite.amerp.system.common.servcode.dao.SysCoServcodeDAO;
import cn.hyite.amerp.system.common.servcode.dto.DateUnit;
import cn.hyite.amerp.system.common.servcode.dto.SysCoServcodeDTO;
import cn.hyite.amerp.system.common.servcode.service.ISysCoServcodeService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import java.text.NumberFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects; /**
* sys_co_servcode 业务编码表 服务实现类
*
* @project server
* @author OnCloud9
* @date 2022-12-15
* @version 1.0
*/
@Service("sysCoServcodeService")
public class SysCoServcodeServiceImpl extends BaseService<SysCoServcodeDAO, SysCoServcodeDTO> implements ISysCoServcodeService { private static final Integer PREFIX_LIMIT = 4;
private static final String SPACER = "00";
private static final String FIELD_YEAR = "sc_year";
private static final String FIELD_MONTH = "sc_month";
private static final String FIELD_DAY = "sc_day"; @Override
public String createServiceCode(String servIdent, String codePrefix, DateUnit dateUnit, Integer length) {
/* Step1 校验入参合法性 */
Assert.isTrue(StringUtils.isBlank(servIdent), ResultMessage.NULL_ERROR, "业务标识");
Assert.isTrue(StringUtils.isBlank(codePrefix), ResultMessage.NULL_ERROR, "业务前缀");
final int prefixLen = codePrefix.length();
Assert.isTrue(prefixLen > PREFIX_LIMIT, ResultMessage.CUSTOM_ERROR, "业务前缀长度超出限制!" + prefixLen);
final int dateUnitLength = DateUnit.TOTAL_LENGTH;
Assert.isTrue(prefixLen + dateUnitLength + 1 > length, ResultMessage.CUSTOM_ERROR, "单号总长溢出!"); /* Step2 组建查询条件, 封装日期单位条件 */
QueryWrapper<SysCoServcodeDTO> condition = Wrappers.query();
condition.eq("sc_serv_ident", servIdent);
condition.eq("sc_prifix", codePrefix); LocalDateTime nowTime = LocalDateTime.now();
String year = String.valueOf(nowTime.getYear());
String month = String.valueOf(nowTime.getMonth().getValue());
String day = String.valueOf(nowTime.getDayOfMonth());
switch (dateUnit) {
case YEAR:
condition.eq(FIELD_YEAR, year);
condition.eq(FIELD_MONTH, SPACER);
condition.eq(FIELD_DAY, SPACER);
break;
case MONTH:
condition.eq(FIELD_YEAR, year);
condition.eq(FIELD_MONTH, month);
condition.eq(FIELD_DAY, SPACER);
break;
case DAY:
condition.eq(FIELD_YEAR, year);
condition.eq(FIELD_MONTH, month);
condition.eq(FIELD_DAY, day);
break;
} /* Step3 查询是否存在此规则的建单记录 */
SysCoServcodeDTO serviceCode = baseMapper.selectOne(condition);
boolean isEmpty = Objects.isNull(serviceCode); if (isEmpty) {
/* 二次校验总长度 */
int totalLength = prefixLen + dateUnitLength + 1;
Assert.isTrue(totalLength > length, ResultMessage.CUSTOM_ERROR, "单号总长溢出!(新建时)"); /* 新建记录,新记录时,设置新的日期单位 */
int newNum = 1;
String dateCode = "";
SysCoServcodeDTO newCode = new SysCoServcodeDTO();
newCode.setScServIdent(servIdent);
newCode.setScPrifix(codePrefix);
newCode.setCreateTime(new Date());
newCode.setScNum(newNum);
newCode.setScYear(year);
switch (dateUnit) {
case YEAR:
newCode.setScMonth(SPACER);
newCode.setScDay(SPACER);
dateCode += (year + SPACER + SPACER);
break;
case MONTH:
newCode.setScMonth(month);
newCode.setScDay(SPACER);
dateCode += (year + month + SPACER);
break;
case DAY:
newCode.setScMonth(month);
newCode.setScDay(day);
dateCode += (year + month + day);
break;
}
baseMapper.insert(newCode); int remainLen = length - (prefixLen + dateUnitLength); /* 返回单号 */
return codePrefix + dateCode + formatNumDigit(remainLen, newNum);
} else {
/* 取当前单号 */
Integer currentNum = serviceCode.getScNum();
++ currentNum; /* 更新最新单号 */
serviceCode.setScNum(currentNum);
baseMapper.updateById(serviceCode); String numStr = String.valueOf(currentNum);
final int numLength = numStr.length(); /* 二次校验总长度 */
int totalLength = prefixLen + dateUnitLength + numLength;
Assert.isTrue(totalLength > length, ResultMessage.CUSTOM_ERROR, "单号总长溢出!(更新时)"); int remainLen = length - (prefixLen + dateUnitLength);
/* 返回单号 */
return codePrefix + serviceCode.getScYear() + serviceCode.getScMonth() + serviceCode.getScDay() + formatNumDigit(remainLen, currentNum);
}
} /**
* 计数值补位
* @param remainLen 剩余长度
* @param serial 序列计数值
* @return java.lang.String 补位后的序列值
* @author OnCloud9
* @date 2022/12/15 16:49
*
*/
private String formatNumDigit(int remainLen, int serial) {
NumberFormat formatter = NumberFormat.getNumberInstance();
formatter.setMinimumIntegerDigits(remainLen);
formatter.setGroupingUsed(false);
return formatter.format(serial);
} }
2023年01月10日 更新
业务调整,追加了如下几个需求:
- 年月日 不再占位, 年4位,月6位(年 + 月),日8位 (年 + 月 + 日)
- 支持空项,不填写年月日,
- 年可以支持2位
- 业务标识前缀支持1 - 4位
原来的日期单位枚举类需要扩展枚举项:
package cn.hyite.amerp.system.common.servcode.dto; import lombok.Getter; /**
* 日期单位枚举类
*
* @author OnCloud9
* @version 1.0
* @project amerp-server
* @date 2022年12月15日 14:36
*/
@Getter
public enum DateUnit {
EMPTY(0), /* 空日期,不占用 */ YEAR_DIGIT2(2), /* 2位年份 */
MONTH_DIGIT2(4), /* 2位年份 + 2位月份 */
DAY_DIGIT2(6), /* 2位年份 + 2位月份 + 2日期 */ YEAR(4), /* 4位完整年份 */
MONTH(6), /* 4位完整年份 + 2位月份 */
DAY(8), /* 4位完整年份 + 2位月份 + 2日期 */
; public static final int TOTAL_LENGTH = 8; private final int length; DateUnit(int length) {
this.length = length;
}
}
同样,需要对应这些新的枚举项追加扩展支持:
package cn.hyite.amerp.system.common.servcode.service.impl; import cn.hyite.amerp.common.ResultMessage;
import cn.hyite.amerp.common.service.BaseService;
import cn.hyite.amerp.common.util.Assert;
import cn.hyite.amerp.system.common.servcode.dao.SysCoServcodeDAO;
import cn.hyite.amerp.system.common.servcode.dto.DateUnit;
import cn.hyite.amerp.system.common.servcode.dto.SysCoServcodeDTO;
import cn.hyite.amerp.system.common.servcode.service.ISysCoServcodeService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import java.text.NumberFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects; /**
* sys_co_servcode 业务编码表 服务实现类
*
* @project amerp-server
* @author OnCloud9
* @date 2022-12-15
* @version 1.0
*/
@Service("sysCoServcodeService")
public class SysCoServcodeServiceImpl extends BaseService<SysCoServcodeDAO, SysCoServcodeDTO> implements ISysCoServcodeService { private static final Integer PREFIX_LIMIT = 4;
private static final String SPACER = "00";
private static final String FIELD_YEAR = "sc_year";
private static final String FIELD_MONTH = "sc_month";
private static final String FIELD_DAY = "sc_day"; @Override
public String createServiceCode(String servIdent, String codePrefix, DateUnit dateUnit, Integer length, int initialNum) {
/* Step1 校验入参合法性 */
Assert.isTrue(StringUtils.isBlank(servIdent), ResultMessage.NULL_ERROR, "业务标识");
Assert.isTrue(StringUtils.isBlank(codePrefix), ResultMessage.NULL_ERROR, "业务前缀");
final int prefixLen = codePrefix.length();
Assert.isTrue(prefixLen > PREFIX_LIMIT, ResultMessage.CUSTOM_ERROR, "业务前缀长度超出限制!限制:" + prefixLen);
final int requireLength = prefixLen + dateUnit.getLength() + 2;
Assert.isTrue(requireLength > length, ResultMessage.CUSTOM_ERROR, "单号总长不足! 需要:" + requireLength + ", 提供:" + length); /* Step2 组建查询条件, 封装日期单位条件 */
QueryWrapper<SysCoServcodeDTO> condition = buildQueryWrapper(servIdent, codePrefix, dateUnit); /* Step3 查询是否存在此规则的建单记录 */
SysCoServcodeDTO serviceCode = baseMapper.selectOne(condition);
boolean isEmpty = Objects.isNull(serviceCode); if (isEmpty) {
/* 新建记录,新记录时,设置新的日期单位 */
SysCoServcodeDTO dto = buildNewServCodeDTO(servIdent, codePrefix, dateUnit, initialNum);
baseMapper.insert(dto);
/* 返回单号 */
int remainLen = length - (prefixLen + dateUnit.getLength());
return codePrefix + dto.getDateCode() + formatNumDigit(remainLen, dto.getScNum());
} else {
return doServCodeUpdate(serviceCode, dateUnit, length);
}
} /**
* 计数值补位
* @param remainLen 剩余长度
* @param serial 序列计数值
* @return java.lang.String 补位后的序列值
* @author OnCloud9
* @date 2022/12/15 16:49
*
*/
private String formatNumDigit(int remainLen, int serial) {
NumberFormat formatter = NumberFormat.getNumberInstance();
formatter.setMinimumIntegerDigits(remainLen);
formatter.setGroupingUsed(false);
return formatter.format(serial);
} /**
* 构建查询条件
* @param servIdent 业务标识
* @param codePrefix 单号前缀
* @param dateUnit 日期单位枚举
* @return QueryWrapper<SysCoServcodeDTO> 查询条件
* @author OnCloud9
* @date 2023/1/9 16:01
*
*/
private QueryWrapper<SysCoServcodeDTO> buildQueryWrapper(String servIdent, String codePrefix, DateUnit dateUnit) {
QueryWrapper<SysCoServcodeDTO> condition = Wrappers.query();
condition.eq("sc_serv_ident", servIdent);
condition.eq("sc_prifix", codePrefix); final LocalDateTime nowTime = LocalDateTime.now();
final String year = String.valueOf(nowTime.getYear());
final String yearDigit2 = year.substring(2);
final String month = formatNumDigit(2, nowTime.getMonth().getValue());
final String day = formatNumDigit(2, nowTime.getDayOfMonth()); switch (dateUnit) {
/* 空选项 */
case EMPTY:
condition.eq(FIELD_YEAR, SPACER).eq(FIELD_MONTH, SPACER).eq(FIELD_DAY, SPACER);
break;
/* 完整年月日选项 */
case YEAR:
condition.eq(FIELD_YEAR, year).eq(FIELD_MONTH, SPACER).eq(FIELD_DAY, SPACER);
break;
case MONTH:
condition.eq(FIELD_YEAR, year).eq(FIELD_MONTH, month).eq(FIELD_DAY, SPACER);
break;
case DAY:
condition.eq(FIELD_YEAR, year).eq(FIELD_MONTH, month).eq(FIELD_DAY, day);
break;
/* 2数位年月日选项 */
case YEAR_DIGIT2:
condition.eq(FIELD_YEAR, yearDigit2).eq(FIELD_MONTH, SPACER).eq(FIELD_DAY, SPACER);
break;
case MONTH_DIGIT2:
condition.eq(FIELD_YEAR, yearDigit2).eq(FIELD_MONTH, month).eq(FIELD_DAY, SPACER);
break;
case DAY_DIGIT2:
condition.eq(FIELD_YEAR, yearDigit2).eq(FIELD_MONTH, month).eq(FIELD_DAY, day);
break;
} return condition;
} /**
* 构建一个新的单号规则记录
* @param servIdent 业务标识
* @param codePrefix 单号前缀
* @param dateUnit 日期单位枚举
* @return cn.hyite.amerp.system.common.servcode.dto.SysCoServcodeDTO
* @author OnCloud9
* @date 2023/1/9 16:37
*
*/
private SysCoServcodeDTO buildNewServCodeDTO(String servIdent, String codePrefix, DateUnit dateUnit, int initialNum) {
final LocalDateTime nowTime = LocalDateTime.now();
final String year = String.valueOf(nowTime.getYear());
final String yearDigit2 = year.substring(2);
final String month = formatNumDigit(2, nowTime.getMonth().getValue());
final String day = formatNumDigit(2, nowTime.getDayOfMonth()); String dateCode = null;
SysCoServcodeDTO newCode = new SysCoServcodeDTO();
newCode.setScServIdent(servIdent);
newCode.setScPrifix(codePrefix);
newCode.setCreateTime(new Date());
newCode.setScNum(initialNum); switch (dateUnit) {
case EMPTY: /* 空选项 日期部分不填充 */
newCode.setScYear(SPACER).setScMonth(SPACER).setScDay(SPACER);
dateCode = "";
break;
case YEAR: /* 完整年份 日期部分 2023 */
newCode.setScYear(year).setScMonth(SPACER).setScDay(SPACER);
dateCode = year;
break;
case MONTH: /* 完整月份 日期部分 202301 */
newCode.setScYear(year).setScMonth(month).setScDay(SPACER);
dateCode = year + month;
break;
case DAY: /* 完整日期 日期部分 20230109 */
newCode.setScYear(year).setScMonth(month).setScDay(day);
dateCode = year + month + day;
break;
case YEAR_DIGIT2: /* 位数2年份 日期部分 23 */
newCode.setScYear(yearDigit2).setScMonth(SPACER).setScDay(SPACER);
dateCode = yearDigit2;
break;
case MONTH_DIGIT2: /* 位数2月份 日期部分 2301 */
newCode.setScYear(yearDigit2).setScMonth(month).setScDay(SPACER);
dateCode = yearDigit2 + month;
break;
case DAY_DIGIT2: /* 位数2日期 日期部分 230109 */
newCode.setScYear(yearDigit2).setScMonth(month).setScDay(day);
dateCode = yearDigit2 + month + day;
break;
}
newCode.setDateCode(dateCode);
return newCode;
} /**
* 更新单号记录操作
* @param serviceCode 单号记录实体
* @param dateUnit 日期枚举
* @param length 总长度
* @return java.lang.String 单号
* @author OnCloud9
* @date 2023/1/9 16:44
*
*/
private String doServCodeUpdate(SysCoServcodeDTO serviceCode, DateUnit dateUnit, int length) {
int prefixLen = serviceCode.getScPrifix().length(); /* 取当前单号 */
Integer currentNum = serviceCode.getScNum();
++ currentNum; /* 取单号位数值 */
int numDigits = String.valueOf(currentNum).length(); /* 二次校验总长度 */
int estimateLength = prefixLen + dateUnit.getLength() + numDigits;
Assert.isTrue(estimateLength > length, ResultMessage.CUSTOM_ERROR, "单号总长溢出!(更新时) 需要:" + estimateLength + ", 提供:" + length); /* 更新最新单号 */
serviceCode.setScNum(currentNum);
baseMapper.updateById(serviceCode); /* 返回单号 */
int remainLen = length - (prefixLen + dateUnit.getLength());
String dateCode = null;
switch (dateUnit) {
case EMPTY:
dateCode = "";
break;
case YEAR:
case YEAR_DIGIT2:
dateCode = serviceCode.getScYear();
break;
case MONTH:
case MONTH_DIGIT2:
dateCode = serviceCode.getScYear() + serviceCode.getScMonth();
break;
case DAY:
case DAY_DIGIT2:
dateCode = serviceCode.getScYear() + serviceCode.getScMonth() + serviceCode.getScDay();
break;
}
return serviceCode.getScPrifix() + dateCode + formatNumDigit(remainLen, currentNum);
} }
【Java】单号创建服务的更多相关文章
- ECSHOP和SHOPEX快递单号查询百世快递插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- ECSHOP和SHOPEX快递单号查询顺丰插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- ECSHOP和SHOPEX快递单号查询申通插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- ECSHOP和SHOPEX快递单号查询韵达插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- ECSHOP和SHOPEX快递单号查询国际EMS插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- ECSHOP和SHOPEX快递单号查询德邦插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- ECSHOP和SHOPEX快递单号查询EMS插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- ECSHOP和SHOPEX快递单号查询中通插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- SHOPEX快递单号查询插件圆通V8.2专版
SHOPEX快递物流单号查询插件特色 本SHOPEX快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅急送快递.德邦物流.百世 ...
- ECSHOP快递单号查询插件圆通V8.2专版
本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅急送快递.德邦物流.百世快递.汇通快递.中通快递.天天快递等知 ...
随机推荐
- c# Redis缓存的使用和helper类;
使用背景: 项目中用户频繁访问数据库会导致程序的卡顿,甚至堵塞.使用缓存可以有效的降低用户访问数据库的频次,有效的减少并发的压力.保护后端真实的服务器. 对于开发人员需要方便调用,所以本文提供了hel ...
- 通过Webpack搭建react
安装解析react的相关babel和插件 nmp i -D babel-loader @babel/core @babel/preset-react @babel/preset-env 进行loade ...
- LeetCode 621. 任务调度器 (Java)
题目: 给定一个用字符数组表示的 CPU 需要执行的任务列表.其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务.任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完.C ...
- EF MYSQL DB FIRST 出现2次数据库名
环境:使用ADO设计器添加的数据库实体,运行时出现 :Table 'world.world.city' doesn't exist . world 是mysql的演示数据库. MySql.Data.E ...
- 如何使用JavaScript实现在线Excel附件的上传与下载?
前言 在本地使用Excel时,经常会有需要在Excel中添加一些附件文件的需求,例如在Excel中附带一些Word,CAD图等等.同样的,类比到Web端,现在很多人用的在线Excel是否也可以像本地一 ...
- SpringBoot+Selenium模拟用户操作浏览器
Selenium Selenium是一个用于Web应用程序自动化测试的开源工具套件.它主要用于以下目的: 浏览器自动化:Selenium能够模拟真实用户在不同浏览器(如Chrome.Firefox.I ...
- DotNet Web应用单文件部署系列
目录 一. pubxml文件配置 二. 打包wwwroot文件夹 三. 混淆dll文件 四. csproj文件配置 五. 批处理 六. Windows服务安装 七. ...
- 初识python day1记录
程序语言中的分类 在程序中有分为高级语言Java python go与低级语言C 汇编,每种语言都有自己的规则,但是最终目的都是给计算机识别的,所以他的底层肯定是一些二进制010101,像java/p ...
- 高通平台Android设备各种开机模式的进入与退出
原文地址:https://www.cnblogs.com/we-hjb/p/9784659.html 高通方案的Android设备主要有以下几种开机模式,Android.EDL.Fastboot.Re ...
- 『vulnhub系列』EVILBOX-ONE
『vulnhub系列』EVILBOX-ONE 下载地址: https://www.vulnhub.com/entry/evilbox-one,736/ 信息搜集: 使用nmap探测内网存活主机,发现开 ...