1.javaԴ?源码?ְ?
2.Exception in thread "main" java.lang.NoClassDefFoundError:
3.java 开发中怎么按照效果图 修改app
4.国内有哪些java类的bpm平台?
5.Java代码生成器更新:添加多数据源模式支持
6.Java开发规范:关于提高开发体验的分享记录
javaԴ??ְ?
1.使用完整描述符来准确地描述变量、字段或类。分包
例如,源码使用的分包名称可以是 FirstName、GrandTotal 或 Corporate Customer。源码虽然像 x1、分包文华EMA公式源码y1 或 fn 这样的源码名称较短容易输入,但是分包它们并不提供任何信息指出它们所代表的内容。这样对代码的源码理解、维护和增强会造成一定困难。分包
2.使用适用于领域内的源码术语。
如果您的分包用户将他们的客户称为顾客,则对这个类使用术语Customer来代替Client。源码许多开发人员曾经犯了这样一个错误:当业界或领域中已存在更贴切的分包术语时,他们还冥思苦想,源码准备为一些概念创建通用术语。
3.巧妙节俭地使用缩写。
这表示您应该维护一份标准短格式(缩写)的列表,应该明智地选择它们,并在使用时保持一贯性。例如,如果要使用字 arithmetic 的短格式, 选择 ar、ari 或 art 中的一个,记录下所选的缩写(到底是哪个并不重要),并只使用这一个。
4.使用大小写混合增强名称的可读性。
通常应该使用小写字母,但是将类名和接口名称的第一个字母写成大写,将所有非起始单词的第一个字母也写成大写。
5.将标准首字母缩写词的第一个字母大写。
名称会经常包含标准缩写,如 SQL 表示“Standard Query Language”。诸如表示属性的 sqlDatabase 或表示类的 sQLDatabase 等名称比sQLDatabase 和SQLDatabase 更便于阅读。
6.避免长型名称(最大 个字符比较合适)。
虽然类名 AllImplemented IterfacesAndSubclass 可能是个比较好的类名(当然,在此示例中有些夸张),但是这个名称显然太长,应该把它重命名为较短的名称才好。
7.避免名称过于相似或仅在大小写方面有区别。
不应该同时使用变量名 myObject 和 myObjects,也不应该同时使用 myOraDatabase 和 anORADatabase。
问:我想使用Tab键在输入字段间移动,我该怎么办?
答:当用户必须键入许多文本时,这一功能特别有用。下面的程序将会告诉你如何让用户在输入字段间切换输入焦点:
public boolean keyDown(Event evt,int key)
{
if ((char)key=='\t')
{
Component current_field=(Component)evt.target;
if (current_filed!=last_field)
current_field.nextFocus();
else
first_field.requestFocus();
return true;
}
}
Exception in thread "main" java.lang.NoClassDefFoundError:
é¨è¿å¤©æ´ æ£è§£ã
Javaæ件ç®å½å ¶å®æ¯ä¸ªä¸å°çé®é¢ï¼å¾å¤äººå¦Javaç´æ¥ç¨IDE导è´ä½¿ç¨Javaå å¹´äºé½ä¸äºè§£è¿ä¸ªé®é¢ï¼å¹¸å¥½ä½ æ¯ä»è®°äºæ¬å¼å§ç¼ç çãæ详ç»è§£éç»ä½ å¬å§ã
è¦å®ç°è¯å¥½çå±æ¬¡ç»æï¼å®æ´çJavaæ件åºè¯¥ä½äºä¸ä¸ªæ件夹ï¼å³å ï¼å ï¼è¿ä¸ªæ件夹çååå¿ é¡»æ¯ä½ çJavaæ件第ä¸è¡å®ä¹çpackage pName;è¿å¥æå®çååpNameãä½ ä¹å¯ä»¥ä¸ä½¿ç¨å ï¼ä½ä»¥åçå¼åä¸ä½ ä¼ä½éªå°åå åæ¾Javaæ件çå¿ è¦æ§ã
åæ¶æ件夹æå¨çç®å½ç§°ä¸ºJavaç¨åºçæ ¹ç®å½ï¼å¨ä½ çç¨åºä¸æ ¹ç®å½å°±æ¯F:\ã å½ä½¿ç¨Javaå½ä»¤å¯å¨ç¨åºæ¶ï¼ä½ å¿ é¡»é¦å è¿å ¥æ ¹ç®å½ï¼ä¸ºä»ä¹ï¼è¿è®°å¾å®ä¹ç¯å¢åéæ¶classpath=.;ä¹ï¼.å·ä»£è¡¨äºå½åç®å½ä½ä¸ºæ¥æ¾ç®å½ï¼åªæä½ è¿å ¥äºæ ¹ç®å½å®æè½æä¸ºä½ çâå½åç®å½âï¼è¿å°±æ¯ä¸ºä»ä¹ä½ è¦é¦å è¿å ¥ä½ çæ ¹ç®å½F:\ ç¶åæè½æ£ç¡®ä½¿ç¨Javaå½ä»¤ãç®å½é®é¢å¨ä½ 第ä¸å¤©ä½¿ç¨Java就已ç»ééåå¨äºï¼åµåµï¼ã
æ¥çï¼Javaå½ä»¤åé¢æ¥åçæ¯ç±»çå®æ´éå®åï¼èä¸æ¯è·¯å¾åãåå¦ä½ çç±»å¨pNameå ä¸ï¼é£å°±æ¯java pName.H ï¼å½ç¶ä½ 没ææ¾å¨å å ï¼æä»¥ä½ çæ åµæ¯java Hã
å¦æè¿æçé®å¯ä»¥ç»§ç»äº¤æµã
java 开发中怎么按照效果图 修改app
1.0 从SSH和SSM到"4S"SSH:Structs(控制层),hibernate(ORM),Spring
SSM:SpringMVC(控制层),MyBatis(ORM),Spring
以上就是Java服务中最常见的框架思路。这3个最常见的java自增源码框架之间涉及到框架的整合,而且框架本身的使用也涉及到大量的配置,如MyBatis的Mapping文件。如果能去掉这些框架整合的部分,当然不光是这三个框架的整合,实际业务还包括缓存,消息中间件等大量框架的整合,会十分的美好。如果再优化下ORM映射的过程,会更加的美好。于是有了"4S"。
2.0 "4S"工程创建
推荐IntelliJ IDEA构建Spring Boot项目。
3.0 工程包结构设计
提供一种基于4S框架的分包思路,供参考。
1是工程相关的配置信息。
2是数据库相关的业务信息。bean中维护了与数据库表结构对应的信息。repository代替传统的dao层,维护数据库的操作。
3是全局的业务相关的配置信息。包括全局的异常处理,拦截器,工具类,全局缓存。
4是业务的主体。这里只分为2层,controller中是控制层,service中是业务处理主体。
5和/resource/value目录对应。用配置的方式来维护一些常量,类似于之前的constance的作用。
6是程序的入口,因为Spring Boot的配置信息会自动扫描和该文件同级的目录及其子目录的信息,故放在根目录下。
7是前端框架
8是前端页面
9是工程的配置文件
4.0 工程配置
开发环境和测试环境连接的数据库和一些配置信息不同,可以通过在application.properties指定不同的配置文件。
日志配置很简单,在application.properties做点配置即可,列举几条常用的
# 日志地址 logging.file=D:/springBoot/log.log # 日志打印级别 logging.level.org.springframework.web=DEBUG
4.3 常量
/value/JavaBean 和 /resource/value/xxx.properties 建立一一对应的关系。可以通过Bean对象获取xxx.properties中的常量信息。举个例子。
国内有哪些java类的bpm平台?
国内java类的BPM平台如(天翎BPM,,宏天、等)BPM即(业务流程管理)致力于帮助企业搭建基于标准化、数字化、流程化、信息化、体系化的运营机制。帮助企业从以高资金、人力、物资耗费为核心的eps转pdf源码重资产营运模式向以品牌、标准、专利为核心的轻资产营运模式转型。
BPM的价值 :BPM在于帮助企业实现跨组织、跨区域、跨IT系统的全面流程整合,全面提升内部岗位和角色的之间、外部行业供应链之间的协同、营运效率。引导企业将核心KPI定位于努力缩短资金、物资、信息的周转时间。在经营转型方面,BPM流程管理将致力于帮助企业开展行业定位分析,引导企业在总包模式和分包模式中进行精准定位。确保企业梳理出以品牌、标准、知识产权和人力资源为重要组成部分的核心资产,逐步将高资金、高物资、高管理耗用的业务单元进行剥离和分包。最终实现轻资产管理模式的转型。
BPM流程的定位 :BPM流程就是实现企业流程资产管理、流程审计分析、流程优化管理、流程知识管理等全方位的对企业进行体系的流程管理。它是一种以规范化的构造端到端的业务流程,是一个操作性的定位描述,是为需求而设计会随着内外环境的变化而需要同步被优化。
BPM流程运营: 由于企业规模扩大,组织机构会逐渐庞大,分工越来越细,企业官僚化程度也在随着增加,此时企业出现效率的低下情况。具体表现在:组织机构完整,出现部门间合作不畅,跨部门流程工作效率低下,决策时间长;制度流程有但没有达到精细化的程度,流程执行不到位等问题。具备这个特点的企业一般是迅速发展的民营企业和一些国有企业。此类企业业务模式相对稳定,而且通常企业发展比较快,在这个阶段的企业需要通过BPM流程来提高企业的工作效率和流程整合能力。
如(天翎BPM)总体架构参考
Java代码生成器更新:添加多数据源模式支持
哈喽,小伙伴们,一周不见了,在这段时间,我利用下班的闲暇时间更新了一版代码生成器,添加了之前呼声较高的多数据源模式,这样生成的代码可以实现动态切换数据源的功能,多数据源在项目当中还算比较常用的小草语音源码,例如主从读写分离,多库操作等都需要在同一个项目中操作多个数据库,本次更新正是解决了这个痛点,生成代码之后,可以通过注解的方式灵活切换数据源,并且支持多库事务一致性,下面就让我们一起看一下具体的实现效果,顺便讲一下动态多数据源的内部原理!
为了实现多数据源模式,代码生成器对界面进行了调整,如下:
主界面添加了选择数据源的功能,并且现在数据库信息需要点击数据源配置来进行配置,点击后会弹出如下窗口:
在这里我们可以配置数据库信息,配置完毕后点击保存,在主界面即可进行选择,在主界面被选择的数据源将在生成的代码中作为默认数据源使用。
勾选多数据源模式可以生成多数据源模式代码,不勾选则与之前一样,生成的是常规单数据源项目。
总体跟原来区别不大,使用多数据源模式生成代码基本步骤如下:
以下为代码生成器生成的部分代码展示:
多数据源模式下会在 config 包下生成多数据源相关的配置类及切面,如果大家有个性化需求可以通过修改 DynamicDataSourceAspect 切面来实现动态切换逻辑,现有切换逻辑基本足够。
多数据源其实还可以通过代码分包的方式实现,这种方式实现起来易于理解:配置多个数据源,扫描不同的包,创建属于自己的 sqlSessionFactory 和 txManager(事务管理器),在使用的时候可以通过调用不同包下的 mapper 来实现多数据源的效果,但是这种方式的弊端也较为明显,分包稍有不慎便会出错,并且如果想要实现不同数据源下的事务一致性也较为麻烦,在同一个 service 方法中操作多个数据库因此受限。
动态多数据源则不会有以上问题,因此代码生成器选择了动态多数据源的生成模式,利用 aop 实现数据源的动态切换,并且可以保证多库操作事务一致性,后面会详细讲解。
在 idea 中运行生成的代码,启动完毕登录,点击左侧菜单查询:
查看后台日志,发现会切换不同的数据库执行sql:
下面以 springboot 为例,讲一下多数据源内部原理。
动态多数据源的内部原理其实就是 aop,只不过复杂的是 aop 的实现过程。
mybatis 为我们提供了一个抽象类 AbstractRoutingDataSource,通过继承此类,重写 determineCurrentLookupKey 方法可以根据返回值决定当前使用哪个数据源,因此我们创建类 DynamicDataSource 继承 AbstractRoutingDataSource 并重写 determineCurrentLookupKey 方法:
先不忙着实现,如果想要正确匹配数据源,我们还需要向 DynamicDataSource 类中注册数据源,sql充值网站源码所以需要先对数据源进行配置,这里注册两个数据源 db1(mysql) 和 db2(oracle),我们使用枚举值 DB1 和 DB2 作为数据源 db1 和 db2 的 key:
注册数据源 db1 和 db2:
通过以上配置,我们成功向 DynamicDataSource 中注册了 db1 和 db2,如何才能获取当前程序运行中的数据源呢?这就需要我们用到 ThreadLocal,ThreadLocal 可以向当前线程中 set 和 get 值并且不受其他线程影响,而我们服务器的每一个请求都由一个工作线程来处理(nio 模式也是一个请求一个工作线程处理,只是在接收请求的时候使用了 io 多路复用),所以可以使用 ThreadLocal 存储当前工作线程的数据源,ThreadLocal 在很多开源框架中都有使用,主要用于线程隔离。
创建 DynamicDataSourceHolder 类,存储当前线程中的数据源:
然后,实现 determineCurrentLookupKey 方法,一行代码即可:
最后一步,我们要实现数据源的动态切换,则需要自己实现一个数据源动态切面,改变当前线程中的数据源,我们可以使用注解来辅助实现,在切面中通过扫描方法上的注解来得知具体切换到哪个数据源。
创建 DBType 注解:
创建数据源动态切面 DynamicDataSourceAspect:
在数据源切面上需要添加 @Order 注解,值取1,这是因为之前我们配置了动态数据源事务,spring 会因此生成事务代理并且会优先于切面执行,事务代理一旦生成,数据源便被固定,这样我们在切面中切换数据源就会无效,所以切面逻辑需要在事务代理之前执行才可生效。
切面配置完后我们只需要在 service 的方法上使用 DBType 注解便可以动态切换数据源,如下:
至此,动态多数据源基本实现完毕!
使用动态多数据源的同时,也要注意保证事务一致性,大家可能遇到过这种情况,传统单数据源应用中,同一个 service ,在没有开启事务的方法里调用开启事务的方法会导致事务失效,这是因为 spring 只会对相同的 service 代理一次,否则如果在没有开启事务的方法中再次开启自身代理会导致循环依赖问题出现,类似 “无限套娃”:自己代理的方法调用自己代理的另一个方法,并且另一个方法还需要自己的代理。解决此类问题的方法很简单,让调用方开启事务即可,多数据源模式中同样适用。
除此之外,多数据源模式中还存在如下场景:serviceA 中的 A 和 B 方法都开启了事务,但操作的是不同的数据库(ip不同),这个时候 A 调用 B,使用的是 A 的代理,对 B 不适用,便会报错,对此我们可以把 B 方法移入另一个 serviceB 中,在 serviceA 中注入 serviceB ,在 A 方法中使用 serviceB 调用 B 方法,这样执行到 B 方法的时候使用的便是 serviceB 的代理,看起来没有问题,但还有一点遗漏,那就是事务的传播行为。
我们都知道,Spring 中默认的事务传播行为是 required:如果需要开启事务,则开启事务,如果已经开启事务,则加入当前事务。上文中,执行 B 方法的时候虽然使用的是 serviceB 的代理,但是由于其事务传播行为是 required,A 方法执行的时候已经开启了事务,所以导致 B 方法加入到了 A 方法的事务中,但 A 和 B 属于两个不同的数据库,使用相同的事务管理器必然会出现问题。为了解决此问题,我们可以把事务传播行为改为 required_new:如果需要开启事务,则开启事务,并且总是开启新的事务。这样执行 B 方法的时候会开启新的事务,使用的便是 B 所在数据库的事务管理器,B 方法也就可以正常执行了,并且如果 B 出现异常,如果 A 不主动捕获,则 A,B 都会回滚。
也许有人会问,单数据源模式下使用 required 为什么不会有上述问题呢,因为单数据源模式下使用的是同一个数据库,在事务执行过程中,当前事务是共享且通用的,所以没问题。除此之外,使用 required 不必频繁重开事务,也一定程度上提升了系统性能,多数据源模式下由于不同数据库之间事务是完全隔离的,所以才需要使用 required_new 重开事务,当然,也需要根据业务具体场景具体分析,这里讨论的只是较为通用的情况。
代码生成器多数据源模式下使用的事务传播行为正是 required_new,全局配置类如下:
到此为止,我们才算实现了一个完整的动态多数据源功能,可见是有许多技术细节潜藏在里面的,朋友们可以使用代码生成器生成多数据源模式下的代码自行运行体会。
本文到这里就结束了,实现这个多数据源生成功能其实也算花了一番心思,正着写代码容易,反过来生成是真不容易,并且由于最开始做的时候没有考虑到多数据源的情况,导致最开始的设计全都是针对单个数据库的,这次强行在外面包了一层,总归是实现了,在这个过程中,顺便也复习了一下 Spring 的循环依赖,Bean 加载周期等老生常谈的问题,也算有所收获。作为开发人员,我们要多关注一些功能底层的东西,而不是简单的 api 调用,这样才能不断突破瓶颈,取得成长。码字不易,各位看官可以点赞,评论,关注哦,我们下次再见!
关注公众号 螺旋编程极客 获取代码生成器最新动态,同时第一时间解锁更多精彩内容!
Java开发规范:关于提高开发体验的分享记录
前言
大家有没有想过程序员为什么这么累,其实作为一个程序员对于个人来说,技术很重要,但是对于工作来说,编码的习惯比技术更加主要。工作中你面试的大部分技术都不需要用到的。工作中,因为你的编码习惯不好,写的代码质量差,代码冗余重复多,很多无关的代码和业务代码搅在一起,导致了你疲于奔命应付各种问题。
良好的编码习惯加上各种开源的工具可以是提高我们的生产效率,减少很多不必要的加班时间。衡量一个开发人员的产出、质量和效率不是流水线一样计计件越多越好,在我看来有以下几点
可阅读性(团队开发,高效协作)
可拓展性(面对需求更变,高效开发)
健硕性(少点BUG,就算出了BUG更容易定位问题)
本次会议的目标改善大家编码习惯,提高代码可读性与开发效率,降低维护与问题定位的成本
使用开源框架降低不必要的重复造轮子时间
编码规范装一个代码规范插件首先推荐装一个阿里的插件:alibaba-java-coding-guidelines,可以帮你更正很多不健康的写法
POJO类命名规范概念:像DTO、Entity等业务对象统称POJO
关于对象类的后缀,业界没有一个硬性统一,只要做到好理解,同一个项目规范统一就好了,比如实体类,有的项目叫Entity,有的叫Model。以下是我个人觉得最优的方案:
视图对象Result:返参结果,例:OrderResult
视图对象VO:用法跟Result一致,个人觉得Result更有辨识度,所以推荐使用Result
数据对象Entity:跟数据表名对应,例:OrderEntity
业务对象BO:内部使用的类,无需暴露在外面(不能在controller使用)
关于CRUD操作相关DTO的全命名方式推荐格式:{ 业务单词}{ 动作}{ 后缀}.java
例:TeacherQueryDTO、TeacherUpdateDTO
反例:ClasscourseDTO(无法从命名获得业务场景)
Controller编写规范接口返参一定要使用泛型,除非只是返回成功或失败的操作,如:Result<此处一定要写返回的类>
原因:可读性强,调用方可直接查看返回的对象属性,并且Swagger、smart-doc等框架支持自动生成文档
Controller原则上只能做参数校验、属性补充、格式转换等操作,不能写业务逻辑,就算有也不能超过5行
原因:解耦,职责问题,不同的类有不同的职责
领域层若只是返回简单的数据,不需要错误提示的接口,如获取xx详情,可不使用Result<>,直接return对象即可
原因:若不需要错误提示信息,没必要再包一层,直接返回所需对象即可
不建议在Controller类加上@RequestMapping,请直接在方法的@PostMapping或@GetMapping写接口全路径
原因:方便搜索且方便根据业务拆分重构Controller时可随意copy移动代码
禁止使用request.getParameter()获得参数,请直接声明在方法体,若参数过多请使用DTO
原因:可读性,且符合文档自动生成规则
禁止使用Map/JsonObject入参或返参
请不要为了方便就这样写,不利于阅读与维护
不建议使用@PathVariable
原因:调试时(浏览器F)无法直观查看接口的参数名是什么;springmvc下非RESTful的风格的接口响应性能会比RESTful风格高2倍(因为涉及正则解析);另外对URL进行权限控制的时候也不好做
控制代码宽度方法参数数量请控制在4个内,如果不是%肯定以后不会加参数,请建一个DTO,像多条件查询的方法,一定要建对象,不然以后加需求就无线叠加方法参数,后果就是:
另外请控制代码长度,太长的方法请学会换行,原则就是不能出现滚动条,例:
/***获取所有表单模板*@paramformId*@paramonlyShowChecked只返回需填的字段*@return*/List<PduFormListResult>getFormDetail(@Param("formId")intformId,@Param("onlyShowChecked")booleanonlyShowChecked);控制代码高度一个类的代码与方法不宜过多,如果可以预见的是一个类会有很多方法,应该根据单一设计原则进行拆分,比如教师拥有教师资料、教师下单、教师数据同步等等,拆分成多个Service,不建议一个Service完成所有的职责,一个文件行数超过千行后,维护成本会渐渐变高。
一个方法的行数也不应该太多,根据阿里的规范,一个方法超过行就应该拆分出来。
异常处理原则能不使用trycatch就不要使用,大家不要害怕有异常就隐藏掉它,只要交给全局异常处理器就可以了,一切异常往外抛
/***不推荐*/@PostMapping("/test1")publicAjaxResult<TeacherSyncDetailDTO>test1(HttpServletRequestrequest){ try{ //业务代码returnAjaxResult.success();}catch(Exceptione){ returnAjaxResult.fail("错误啦");}}/***推荐*/@PostMapping("/test2")publicAjaxResult<TeacherSyncDetailDTO>test2(Stringid){ if(1!=1){ thrownewNsbCommonException("错误啦");}returnAjaxResult.success();}原因:业务代码不应该自己捕获异常,不要关心异常怎么处理,交给全局处理器来处理,这也是职责的问题,解耦代码,错误的日志、邮件通知等等的逻辑可以交给全局异常处理器记录,这样就可以做到代码的复用,更重要的是代码美观,可读性更强。
比方说我要对某个异常出现时特殊处理,比如发邮件,如果用trycatch那是不是我要写很多重复的代码?就算你封装成一个方法,那也得在很多的catch中调用,那也一点都不优雅。
//例:业务异常,尽情往外抛@TransactionalpublicvoidsubmitUnConfirm(OrderTourConfirmDTOdto){ OrderBaseModelbase=orderBaseService.getByOrderNum(dto.getOrdernumber());OrderTourModelorder=this.getByOrderNum(dto.getOrdernumber());if(!order.getStatus().equals(OrderTourStatusConst.REVIEW)){ thrownewCommonException("提交失败,该订单非审核中状态");}if(base.getAdultQty()==null||base.getAdultQty()==0){ thrownewCommonException("提交失败,请填写订单的成人数、儿童数");}if(base.getPduId()==null){ thrownewCommonException("提交失败,请选择商品和规格");}order.setStatus(OrderTourStatusConst.APPOINT);order.setSubmitTime(newDate());this.updateById(order);}合理的注释这个大家都懂,只要你维护过没有注释的代码你就明白这个事情的重要性。
在此提出几个建议
重要流程请加上注释
无用的代码请删掉,不要一顿注释就完事
废弃但不能删除的代码请使用@Deprecated告知
可分模块的流程善用分割符=========优雅的注释可以降低很多维护成本
关于service层的写法我们在定义Service层的时候有两种常规做法:
直接一个service实现类
定义service接口+serviceImpl实现类
思考1:使用service在日常业务开发中,在常规的三层架构(controller+service+mapper)中写业务,使用service+serviceImpl其实没有带来设计上的优点和使用interface的初衷,反而带来一些不必要的工作量。
开发/维护的时候我需要改2个文件,实现类也没法直观查看接口注释,浪费了一些开发时间,而且阅读的代码的时候链路多了一层
在大部分业务开发场景不需要一个service一个impl,因为你的实现类基本只有一个,无法体现接口的初衷,也没有所谓的解耦
这里有一篇更完整的文章大家可以看看:/s/ykEno7L5Xr1VHQ-ItQ-FYQ
所以大部分开发业务的场景,并不需要使用interface定义一层接口,如果不需要多实现,也没有用到设计模式去解耦,直接定义一个实现的Service其实开发效率更高
当然了,也有缺点就是:
不用使用接口,使用this.xx()调用本类方法会使AOP失效,如事务;当然也有解决方法,有兴趣自行百度。
当一个类的方法太多的时候,不方便查阅,但其实可以缩进,而且一个service层不应该承担太多的职责,代码行数是可控的
思考2:使用service+serviceImpl其实网上很多开源项目大多数都是使用service+serviceImpl,只是我觉我们日常业务开发没有把这种模式的优势发挥出来,比如:
需要用到一些设计模式,比如策略模式、工厂模式等
我和同事分别做项目的2个不同功能模块,但是同事的功能中却需要调用我这头实现的部分逻辑.为了让他有一个"占位符"可用,我可以快速的写个接口扔给他
某个service需要多继承
结论引用网络上的文章:这些情况其实可以说是接口好处的体现,所以java有面向接口编程的建议.但是说回Service层一定要有接口吗?那到未必,因为说到底,多一个接口仅仅是扩展性和某些情况下有优势,但是是否会用到接口的便利性,不确定的情况下我们未必一定要为"可能"买单.只是多写那几行代码,付出一点就可能避免"未来"的大"麻烦",何乐而不为
所以这里给到的建议是根据实际情况按需使用。
工具类编写规范相信大家都知道Hutool这个神器,建议写工具类的时候去看看这个文档,如果有重复的就不要再造轮子了
但是如果遇到没有的呢,比如在做学段学科需求的时候发现,CollUtil就没有取两List的笛卡尔积,那请新建一个ExtCollUtil,并且继承它,这个类即同时拥有hutool的方法,也有自定义的方法。
PS:其实公司应该有自己一个工具工程,原则上开发人员不可以偷偷在各自的工程写Util,若有需要提PR到专门的工具类工程,可以有效降低重复造轮子的时间
Lombok更优雅的用法Lombok相信大家都会用,但除了@Data还有更多优雅的用法
在对象上加上注释@Accessors(chain=true),可以使用链式写法
this.save(newMemTeacherEntity().setId("id").setTeacherTypeName("名字"));@RequiredArgsConstructor替代@Autowired构造注入,多个bean注入时更加清晰
@RequiredArgsConstructor@ServicepublicclassMemTeacherSyncService{ privatefinalMemTeacherServicememTeacherService;privatefinalMemTeacherEduServicememTeacherEduService;}@CleanUp清理流对象,不用手动去关闭流
@CleanupOutputStreamoutStream=newFileOutputStream(newFile("text.txt"));@CleanupInputStreaminStream=newFileInputStream(newFile("text2.txt"));byte[]b=newbyte[];while(true){ intr=inStream.read(b);if(r==-1)break;outStream.write(b,0,r);}包分级与类的存放合理的代码结构可有效降低代码的维护成本,在常规的项目中一般有2种存放的思路
按照技术角度或者文件类型来分(by-techorby-type),下文简称by-tech
按照业务功能来分(by-featureorby-business),下文简称by-biz
先了解一下这两者具体是什么
by-tech以文件类型作为顶层包,其次再以业务进行划分
com└─github└─heys1├─common│├─exction│└─util├─controller│├─student│└─teacher└─service├─student└─teacherby-biz以业务作为顶层包,其次再以文件类型进行划分
com└─github└─heys1├─common│├─exction│└─util├─controller│├─student│└─teacher└─modular├─student│├─dto│├─mapper│└─service└─teacher├─dto├─mapper└─service使用modular/modules根据业务对类进行拆分
controller比较特殊类似聚合层,可以按by-biz拆分,也可按by-tech拆分,根据业务情况选择即可
通用的util、异常、处理器、拦截器等等放在common包
如何选择在我以往的项目中我是采用第二种,理由如下:
开发方便,只需在一个包下即可开发,左侧的IDE菜单无需切来切去;
要添加或者移除一块业务时通常更加方便。比如大的应用做拆分,一般都是按照业务功能拆分的,则直接拆出某个包到新应用即可;
通过应用的包结构目录,就能大致知道这个模块在做什么,贴近DDD的思想,以controller作为聚合层、module作为领域层,结构清晰。
在《聊一聊DDD应用的代码结构》一文中作者写到:
按照业务来分包的思路在网上占绝对优势
所以建议选择方案二。