前言
本文章用于记录个人开发的一些笔记
一、需求前期准备工作
TAPD上查看需求,gitlab上面创建属于自己的单独分支(分支最好以-yyyy-MM-dd作为后缀),然后拉取最新代码,本地idea切换分支进行开发。
常用命令 git pull 拉取
git push 推送
git checkout xxxx 切换分支
二、需求实现阶段
1.关于代码编写方面
- 代码要书写规范,命名要言简意赅,mapper,service层方法命名可以参考mybatisplus。
- 得到的集合结果集也要见名知意,如existlist 等
- 具体命名规范可参考java开发手册
- 常量类大写,动态配置类小写驼峰
2.代码细节方面
1.数据库数据处理方面
注意数据库能不全表扫描就别全表扫描,执行计划查看索引是否使用,尽量带条件查询
- 合理运用stream流,lamda表达式可以大幅度简化代码。
- 尽量避免在for循环中重复操作db,可以一次性查出来放入缓存中,如map,redis等。
- 数据量过大时,不要一次查出数据放入for中做比较,可以将我们要比较的数据当做数据库条件查询。在进行数据库操作时,能在数据库进行过滤的尽量在数据库过滤,避免一次性读取过多数据。
- 数据库进行新增时,如果数据量过大,可进行批量操作,每100作为一个档次
List<List<MobileBlackDO>> totalList = Lists.partition(mobileBlackDOList, MobileBlackConstant.ADD_MOBILE_BATCH_MAX_SIZE);
totalList.forEach(singleList -> mobileBlackMapper.insertBatch(singleList));
对于有增删改多个操作时得加上事务,如图
@Transactional(rollbackFor = Throwable.class)
public void execute(ShardingContext shardingContext) {
log.info("开始准备刷上行短信到黑名单");
addMobileBlack();
log.info("刷上行短信到黑名单结束");
}
如果数据库数据量过大,一次查出来不方便,可分多次查询,一次可2000但是得一次性查到底,不可只查部分数据。如一开始记录本次id,具体代码如下
//获取上次记录id,取出数据
Long lastSmsUplinkId = smsUplinkIndexService.selectLastSmsUplinkId();
List<SmsUplinkDO> collectList = new ArrayList<>();
do {
lastSmsUplinkId = smsUplinkService.selectIdByMarket(lastSmsUplinkId, MobileBlackConstant.ADD_MOBILE_PAGE_SIZE, collectList);
} while (lastSmsUplinkId != null);
//获取黑名单限制条件,过滤黑名单得到黑名单数据
@Override
public Long selectIdByMarket(Long lastSmsUplinkId, int pageSize, List<SmsUplinkDO> collectList) {
List<SmsUplinkDO> existMarketList = smsUplinkMapper.selectByMarket(lastSmsUplinkId, pageSize);
if (CollectionUtils.isEmpty(existMarketList)) {
return null;
}
collectList.addAll(existMarketList);
return existMarketList.get(existMarketList.size() - 1).getId();
}
mapper要根据id排序,方便取出id,尽量避免子查询。
2.查询结果集方面
- 取出来的集合或者map如果接下来对他要进行判断操作,可以利用工具类进行非空判断。比如commonlang3包下面的collectionutils.isempey,或者stirngutils,如需返回结果为空,可利用collections.emptylist;
CollectionUtils.isEmpty(); StringUtils.isNotBlank(); Collections.emptyList(); BeanUtils.copyProperties();
3.其他
- 方法返回结果需要什么数据就返回什么数据,不需要service层返回controller所需数据
- 不要使用魔法数字,可放入该模块的常量类中。
- 不要在for中删除集合元素,应使用迭代器
- 在配置中心的项,如果后续有db操作,现判断是否有值 没值直接跳过不需要db操作。
- list集合contain方法是用迭代器进行遍历,使用set效率更高,set使用hasmap实现
- 对于for循环里面多个同一操作,可以提取在for循环外部进行。
- 嵌套不要太多层可以优化代码,必要时进行方法抽取
三、需求发布阶段
注意事项:配置中心数据一定要每个环境都得配上
配置中心默认pro环境,修改时得看清环境修改,不要修改别人配置
- 在dev环境测试完毕后,可在jenkins上打包发布,在ops上面发布到测试环境。如果有配置中心,也需将其发布到test的配置中心上。
- 先进行数据库ddl,dml的发布,保存文件在本地,提交到代码上。如果ops5即可走sql审核,审核完毕后即可发布。
- 配置中心数据一起发布,前面准备完成后
- 开始发布代码到pro环境。
pro环境需要审核,审核完毕才可发布!!!
发布后可到kinba上查看具体日志信息
为什么要使用分布式调度
- scheduled是单机分布式任务,如果每台机器都需要执行就可以使用scheduled。比如刷新到本地缓存,本地缓存是独有的因此每台机器都得需要。
- elastic-job是微服务的定时任务调度,更适合于不需要每台机器都执行的任务。比如刷新到mysql或者redis等操作,只需要一台机器执行即可,可配置策略,指定机器执行,而不是每台机器都执行。而且可以加快执行速度,负载均衡
- 对于数据量太大的任务就进行分片,加快处理速度
总结说就是:
- 为了将大的拆成小的,分成多份各自执行各自的,但是都是为了完成一个需求
- 集群中都是同样功能,但是定时器只需要其中一个进行执行就可以
🔗https://blog.csdn.net/qq_42370967/article/details/119707981
四、mybatisplus
mybatis返回的map是只能返回一个的,遇到多的就会报错,会将select后面的字段的名称作为key,值作为value。
五、小结
类的初始化会一开始就保证给所有成员变量初始化,然后再掉对应的初始化语句,其次才是构造函数初始化。
双重for循环不可取,少用,如果要比较里面的属性,可以使用map,然后map.get获取
利用URLConnection来发送POST和GET请求 - 晴空~万里 - 博客园
springSecurity学习笔记
https://download.csdn.net/download/weixin_46365049/87274480
SpringSecurity学习记录(WebSecurityConfigurerAdapter被弃用,SecurityConfig新玩法)_学习_还有很多事要做啊.-DevPress官方社区
响应写出工具类
public static void write(HttpServletResponse response, Object result) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-type", "application/json;charset=UTF-8");
response.setStatus(200);
try (PrintWriter writer = response.getWriter()) {
writer.write(JSON.toJSONString(result));
writer.flush();
} catch (IOException ex) {
log.error("response write detected error", ex);
}
}
bean复制工具类
@Data
@Slf4j
public final class BeanCopyUtils {
private BeanCopyUtils() {
}
/**
* 复制单个bean
*/
public static <S, T> T copyBean(S sourceBean, Class<T> targetClass) {
try {
T t = targetClass.newInstance();
BeanUtils.copyProperties(sourceBean, t);
System.out.println(10 / 0);
return t;
} catch (Exception e) {
e.printStackTrace();
log.info("错误:{}", e.getMessage());
return null;
}
}
/**
* 复制list集合
*/
public static <S, T> List<T> copyList(List<S> sourceList, Class<T> targetClass) {
return sourceList.stream().map(s -> copyBean(s, targetClass)).filter(Objects::nonNull).collect(Collectors.toList());
}
public static void main(String[] args) {
Student student = new Student("zs", "男");
System.out.println(copyBean(student, Person.class));
List<Student> students = Arrays.asList(student, new Student("xiaohong", "女"));
System.out.println(copyList(students, Person.class));
}
}
vo可以复用,可以在每个do里面写一个静态方法转成vo,然后查询详情和查询list的可以服用。
dto也可以复用,没必要一个crud接口写一个dto或者vo。
controller 命名简单明了
eg: querylist queryInfo
更新或者新增接口 DTO接受 查询接口xxxQuery接收 返回参数VO返回
。service参考mp
分页:
/**
* @author pengxiaoxi
* @Description
* @date 2022/12/21 18:01
**/
@Data
public class PageParameter implements Serializable {
private static final long serialVersionUID = 5393527808721863129L;
private static final Integer DEFAULT_PAGE_SIZE = 10;
private Integer currentPage;
private Integer pageSize;
private Integer prePage;
private Integer nextPage;
private Integer offset;
private Integer totalCount;
private Integer totalPage;
public PageParameter() {
this.currentPage = 1;
this.pageSize = DEFAULT_PAGE_SIZE;
}
public PageParameter(final Integer currentPage, final Integer pageSize) {
this.currentPage = Objects.isNull(currentPage) || currentPage <= 0 ? 1 : currentPage;
this.pageSize = Objects.isNull(pageSize) || pageSize <= 0 ? DEFAULT_PAGE_SIZE : pageSize;
this.offset = (this.currentPage - 1) * this.pageSize;
}
public PageParameter(final Integer currentPage, final Integer pageSize, final Integer totalPage) {
this.currentPage = Objects.isNull(currentPage) || currentPage <= 0 ? 1 : currentPage;
this.pageSize = Objects.isNull(pageSize) || pageSize <= 0 ? DEFAULT_PAGE_SIZE : pageSize;
this.offset = (this.currentPage - 1) * this.pageSize;
this.prePage = currentPage <= 1 ? 1 : currentPage - 1;
this.totalPage = (int) Math.ceil((double) totalPage / (double) this.pageSize);
this.nextPage = this.currentPage >= totalPage ? totalPage : this.currentPage + 1;
this.totalCount = totalPage;
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonPager<T> implements Serializable {
private static final long serialVersionUID = -6143244580674359019L;
private List<T> dataList;
private Integer count;
}
public class PageResultUtils implements Serializable {
private static final long serialVersionUID = 714852774118107467L;
public static <T> CommonPager<T> result(final Supplier<List<T>> listSupplier, final Supplier<Integer> countSupplier) {
Integer count = countSupplier.get();
if (Objects.isNull(count) || count <= 0) {
return new CommonPager<>(Collections.emptyList(), 0);
}
return new CommonPager<>(listSupplier.get(), count);
}
}
实现applicationaware接口注入上下文
public class ApplicationContextAware implements org.springframework.context.ApplicationContextAware, BeanNameAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
doSetApplicationContext(applicationContext);
}
private static void doSetApplicationContext(ApplicationContext applicationContext) {
ApplicationContextAware.applicationContext = applicationContext;
}
public static <T> T getByClass(Class<T> tClass) {
return applicationContext.getBean(tClass);
}
@Override
public void setBeanName(String s) {
}
}
总结
简单记录,间隔更新