java开发杂项总结
java开发小白杂项总结
前言:本人毕业于2021年,刚刚接触java开发,在开发过程中发现自己什么都不懂,因此写下本文作为总结自己在初入开发时遇到的问题,希望有机会看到本文的家人们,避免踩我相同的坑(有些坑自己都觉得傻,本文等于小白成长日志)。本文包括一些java写法,规范,报错问题,常见问题等杂项,希望能帮助各位和我一样刚步入java开发的小伙伴。文中有什么不对的,也希望大家不吝指点。这也是我第一次尝试写博文,一些排版等问题日后也会向大家多多学习。星光不问赶路人 时光不负有心人(本文持续更新)
一、java
1.java8新特性
(1)stream流式操作
//使用流过滤public static void main(String[] args) { List<String> list = new ArrayList<>();list.add("张无忌");list.add("周芷若");list.add("赵敏");list.add("张强");list.add("张三丰");list.stream().filter(s->s.startsWith("张")).filter(s-> s.length() == 3).forEach(System.out::println);//流map //1.将流中的元素映射到另一个流中,这个是在后期经常用到的,比如方法所接收的返回值是A,但是接收的却是Blist.stream().map(item -> {ProductInfoAttributes productInfoAttributes = new ProductInfoAttributes();BeanUtils.copyProperties(item, productInfoAttributes);productInfoAttributes.setProductId(productId);productInfoAttributes.setAttributeId(IDGenerator.getId());return productInfoAttributes;}).collect(Collectors.toList());//2.将String类型的流转换为Integer 类型Stream<String> stringStream = Stream.of("1", "2", "3", "4", "5", "6");stringStream.map(str->Integer.parseInt(str)).forEach(System.out::println);//3.方法需要返回的是List <String>,但是这里只有List<Category>,此时就要想到stream().mappublic List<String> queryNamesByIds(List<Long> ids){List<Category> categories = this.categoryMapper.selectByIdList(ids);return categories.stream().map(category -> category.getName()).collect(Collectors.toList());}
2.static使用(与属性注入的关系)
(1)static(主函数是static修饰)只能调用调用static方法
静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
public abstract class A {public static void func1(){}// public abstract static void func2(); // Illegal combination of modifiers: 'abstract' and 'static'
}
只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字,因为这两个关键字与具体对象关联。
public class A {private static int x;private int y;public static void func1(){int a = x;// int b = y; // Non-static field 'y' cannot be referenced from a static context// int b = this.y; // 'A.this' cannot be referenced from a static context}
}
(2) 静态内部类(从类的加载顺序可知【加载原则先静态后非静态,先父类再子类】)
非静态内部类依赖于外部类的实例,也就是说需要先创建外部类实例,才能用这个实例去创建非静态内部类。而静态内部类不需要。
public class OuterClass {class InnerClass {}static class StaticInnerClass {}public static void main(String[] args) {// InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static contextOuterClass outerClass = new OuterClass();InnerClass innerClass = outerClass.new InnerClass();StaticInnerClass staticInnerClass = new StaticInnerClass();}
}
静态内部类不能访问外部类的非静态的变量和方法。不应该通过类实例访问静态成员,使用类名去访问
父类(静态变量、静态语句块)
子类(静态变量、静态语句块)
父类(实例变量、普通语句块)
父类(构造函数)
子类(实例变量、普通语句块)
子类(构造函数)
3.集合
(1)List中add和addAll的区别
add是添加list对象,addAll是添加list中的每一个object
4.java常用API(常看api文档)
JDK1.8源码中文说明
http://blog.fondme.cn/apidoc/jdk-1.8-google
1.集合(工具类)
ArrayList<JSONObject> result = Lists.newArrayList();List<LfCategory> list = lfCommodityInfoPlMapper.findTypeList(LfType.VIDEO);list.addAll(lfCommodityInfoPlMapper.findTypeList(LfType.GAME));lists.newarraylist():List<String> list = new ArrayList<String>(); new arraylist() :List<String> list = Lists.newArrayList();//Lists和Maps是两个工具类, Lists.newArrayList()其实和new ArrayList()几乎一模一样, 唯一它帮你做的(其实是javac帮你做的), 就是自动推导(不是"倒")尖括号里的数据类型.
2.Arrays
//转string
Arrays.toString
3.Collections
//判断是否为空
Collections.isEmpty
5.IO流
(1)读文件(输入流):
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("infilename")));
不管你从磁盘读,从网络读,或者从键盘读,读到内存,就是InputStream。
(2)写文件(输出流):
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("outfilename")));
不管你写倒磁盘,写到网络,或者写到屏幕,都是OuputStream
6.java自带util
//CollectionUtils,集合工具类 https://blog.csdn.net/huangwenyi1010/article/details/53706297
//交并补差,是否相等,是否为空等等
CollectionUtils.isEmpty(childCategoryList);//StringUtils,字符工具类
StringUtils.isEmpty();
二、Mysql
1)外连接查询/函数运用到相应的列
<select id="findByUid" resultType="cn.hutool.json.JSONObject">select loi.order_no orderNo,loi.unit_price totalPrice,loi.account phone,loi.order_status status,lon.order_info cardInfo,lc.icon,lc.id categoryId,//三元表达式IF(loi.sec_kill = 1, lcip.name, lci.name) commodityName,IF(loi.sec_kill = 1, lcip.type, lci.type) type,loi.created,//从该列的左边开始计算到第19位LEFT(aon.gmt_payment, 19) payTimefrom lf_order_info loileft join lf_commodity_info lci on loi.code = lci.codeleft join lf_commodity_info_pl lcip on loi.code = lcip.codeleft join lf_category lc on lci.category = lc.idleft join lf_order_notify lon on loi.order_no = lon.out_idleft join alipay_order_notify aon on loi.order_no = aon.out_trade_nowhere loi.uid = #{uid}GROUP BY loi.idorder by loi.created desc</select>
2)模糊查询写法
name like concat(‘%’,#{name},‘%’);
3)foreach/trim区别
//循环数组,开闭,分隔器
<foreach item="id" collection="array" open="(" separator="," close=")">#{id}
</foreach>
/**
trim(剪切的用法)
<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>
prefix:在trim标签内sql语句加上前缀。
suffix: 在trim标签内sql语句加上后缀。
suffixOverrides:指定去除多余的后缀内容,如:suffixOverrides=",",去除trim标签内sql语句多余的后缀","。
prefixOverrides: 指定去除多余的前缀内容
**/<insert id="insertLfCommodityInfo" parameterType="com.xfw.welfare.docking.lf.domain.LfCommodityInfo">insert into lf_commodity_info<trim prefix="(" suffix=")" suffixOverrides=","><if test="code != null">code,</if><if test="name != null">name,</if><if test="valueStr != null">value_str,</if><if test="typeCode != null">type_code,</if><if test="memberType != null">member_type,</if><if test="price != null">price,</if><if test="category != null">category,</if><if test="underlinedPrice != null">underlined_price,</if><if test="sellingPrice != null">selling_price,</if><if test="type != null">type,</if><if test="enable != null">enable,</if><if test="created != null">created,</if><if test="updated != null">updated,</if><if test="taxRate != null">tax_rate,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="code != null">#{code},</if><if test="name != null">#{name},</if><if test="valueStr != null">#{valueStr},</if><if test="typeCode != null">#{typeCode},</if><if test="memberType != null">#{memberType},</if><if test="price != null">#{price},</if><if test="category != null">#{category},</if><if test="underlinedPrice != null">#{underlinedPrice},</if><if test="sellingPrice != null">#{sellingPrice},</if><if test="type != null">#{type},</if><if test="enable != null">#{enable},</if><if test="created != null">#{created},</if><if test="updated != null">#{updated},</if><if test="taxRate != null">#{taxRate},</if></trim></insert>
4)Mybatis插入list集合
insert into lf_commodity_info(id,code,name,value_str,type_code,member_type,category,price,underlined_price,selling_price,type,enable,tax_rate,created,updated)values<foreach collection="list" index="index" item="item" separator=",">(#{item.id},#{item.code},#{item.name},#{item.valueStr},#{item.typeCode},#{item.memberType},#{item.category},#{item.price},#{item.underlinedPrice},#{item.sellingPrice},#{item.type},#{item.enable},#{item.taxRate},#{item.created},#{item.updated})</foreach>//sql语句
INSERT INTO student(name,age,sex)
VALUES("张三",12,"男"),("王三",12,"男")
5)关联查询
select iconfrom lf_category aright join lf_commodity_info b on a.type=b.typewhere b.category = #{category}
5.1.sql左联右联的差别
左联接:已一边为主表保留其全部数据
6)嵌套查询
select iconfrom lf_category awhere a.type = (select typefrom lf_commodity_info bwhere b.category = #{category})
7)distinct关键字去重
//distinct去重查询
select iconfrom lf_category awhere a.type = (select DISTINCT type from lf_commodity_info b where b.category = #{category})//关联查询的去重 SELECTa.id,a.title,a.total,count( DISTINCT ( b.user_id ) ) AS 'read',//去重后计算该类别中的总数a.time,a.status
FROMmessage aRIGHT JOIN msg_read b ON a.id = b.msg_idGROUP BY a.id//巧用分组,分组计算
三、Spring全家桶
1.注解
(1)Spring中异步注解@Async的使用、原理及使用时可能导致的问题
(2)
@requestBody(将json转成object对象,前端到后端交互时使用)
注解@RequestBody接收的参数是来自requestBody中,即请求体。一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml等类型的数据。
@RequestParam():@RequestParam
注解@RequestParam接收的参数是来自HTTP请求体或请求url的QueryString中。
RequestParam可以接受简单类型的属性,也可以接受对象类型。
@RequestParam有三个配置参数:
required 表示是否必须,默认为 true,必须。
defaultValue 可设置请求参数的默认值。
value 为接收url的参数名(相当于key值)
(3)@PathVariable(接收类如aaa/{id})直接在url后的参数
(4)@Cacheable(用于缓存注解)
@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,这个稍后会进行说明。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。
(5)@Configration
@ConfigrationProperties(prefix=“lf”) //配置类的注解
(6)@RequestMapping请求和别的区别
@RequestMapping(name = " 支付宝 支付返回数据", value = "/aliPay/return_url", method = {RequestMethod.POST, RequestMethod.GET})
2.OpenFeign的使用
创建应用主类Application,并通过@EnableFeignClients注解开启Spring Cloud Feign的支持功能。
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients(basePackages = { "com.kyle.client.feign.inter" })
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
▪️定义HelloServiceFeign,接口@FeignClient注解指定服务名来绑定服务,然后再使用Spring MVC的注解来绑定具体该服务提供的REST接口。
@FeignClient(value = "hello-service-provider")
public interface HelloServiceFeign {@RequestMapping(value = "/demo/getHost", method = RequestMethod.GET)public String getHost(String name);@RequestMapping(value = "/demo/postPerson", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")public Person postPerson(String name);
}
注意:这里服务名不区分大小写,所以使用hello-service-provider和HELLO-SERVICE-PROVIDER都是可以的。另外,在Brixton.SR5版本中,原有的serviceId属性已经被废弃,若要写属性名,可以使用name或value。
▪️接着,创建一个RestClientController来实现对Feign客户端的调用。使用@Autowired直接注入上面定义的HelloServiceFeign实例,并在postPerson函数中调用这个绑定了hello-service服务接口的客户端来向该服务发起/hello接口的调用。
@RestController
public class RestClientController {@Autowired
private HelloServiceFeign client;/*** @param name* @return Person* @Description: 测试服务提供者post接口* @create date 2018年5月19日上午9:44:08*/
@RequestMapping(value = "/client/postPerson", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
public Person postPerson(String name) {return client.postPerson(name);
}/*** @param name* @return String* @Description: 测试服务提供者get接口* @create date 2018年5月19日上午9:46:34*/
@RequestMapping(value = "/client/getHost", method = RequestMethod.GET)
public String getHost(String name) {return client.getHost(name);
MyDev
//添加注解,实现api接口
@RestController
public class IfClient implements LfHandleApi {@Resourceprivate LfCommodityInfoMapper lfCommodityInfoMapper;@Resourceprivate DocLfPayService lfPayService;@Resourceprivate LfCategoryMapper lfCategoryMapper;/****在璐付平台进行支付* @param lfOrderInfo* @author xusj* <br>CreateDate 2022/1/4 10:06*/@Overridepublic void pay(LfOrderInfo lfOrderInfo) {//查找商品LfCommodityInfo commodityInfo = lfCommodityInfoMapper.findByCode(lfOrderInfo.getCode());if (commodityInfo == null) {throw new BizException(ErrorMessages.BASIC_0001, "商品不存在");}switch (commodityInfo.getType()) {case LfType.VIDEO:lfPayService.payVideo(commodityInfo, lfOrderInfo.getAccount(), lfOrderInfo.getOrderNo());break;case LfType.GAME:case LfType.RECHARGE_CARD:lfPayService.payGame(commodityInfo, lfOrderInfo.getAccount(), lfOrderInfo.getIp(), lfOrderInfo.getOrderNo());break;case LfType.PHONE_BILL:lfPayService.payMobile(commodityInfo, lfOrderInfo.getAccount(), lfOrderInfo.getOrderNo());break;default:throw new BizException(ErrorMessages.BASIC_0001, "商品类型不存在!");}}@Overridepublic LfCommodityInfo findByCode(String code) {//通过code查询LfCommodityInfo lfCommodityInfo = lfCommodityInfoMapper.findByCode(code);return lfCommodityInfo;}@Overridepublic String getIcon(Long category) {return lfCategoryMapper.selectIcon(category);}
@EnableFeignClients//远程调用入口
@SpringBootApplication
@MapperScan(value = "com.xfw.welfare.docking.lf.mapper")
public class DockingApplication {public static void main(String[] args) {SpringApplication.run(DockingApplication.class, args);}}
//api模块,去调用别的模块,定义api接口
@FeignClient(value = "${lf.namespace:}lf")
public interface LfHandleApi {/*** description: 调用璐付支付接口** @param lfOrderInfo 璐付订单信息* @author xieran* @date 2021/12/29 14:18*/@GetMapping("/api/welfare-lf/pay")void pay(@RequestBody LfOrderInfo lfOrderInfo);/*** description:获取lf商品** @param code code* @return com.xfw.welfare.docking.lf.domain.LfCommodityInfo* @author xr* @date 2022/1/4 9:56 上午*/@GetMapping("/api/welfare-lf/findByCode")LfCommodityInfo findByCode(String code);/*** description:查询产品icon** @param category 类别id* @return java.lang.String* @author xr* @date 2022/1/4 4:45 下午*/@GetMapping("/api/welfare-lf/getIcon")String getIcon(@RequestParam("category") Long category);
}
理解feign的代码架构方式
三层架构的理解,lfclient,DocLfPayservice,DocLfPayserviceimpl 区别
一、远程调用类再主服务中,实现api中api接口方法(这里写url),需要注解@RestController,类似于实现类
3.@Scheduled定时任务cron表达式
定时任务Scheduled
cron表达式详解https://help.eset.com/era_admin/65/zh-CN/cron_expression.html
@Component
public class Task
{@Scheduled(cron="0/5 * * * * ? ") //每5秒执行一次public void execute(){SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置日期格式System.out.println("欢迎访问 pan_junbiao的博客 " + df.format(new Date()));}//启动类添加注解
@SpringBootApplication
@EnableScheduling //开启定时任务
public class ScheduledDemoApplication
{public static void main(String[] args){SpringApplication.run(ScheduledDemoApplication.class, args);}
4.配置文件的使用
server: //端口port: ${APP_PORT:19970}spring:application:name: ${order-server.namespace:}ordercloud:nacos:username: ${NACOS_SERVER_USERNAME:nacos}password: ${NACOS_SERVER_PASSWORD:xfw1234}server-addr: ${NACOS_SERVER_ADDR:172.16.9.159:8848}config: //nacos中配置的前缀和yml后缀prefix: orderenabled: truefile-extension: ymldiscovery:enabled: trueprofiles:active: @profiles.active@main:allow-bean-definition-overriding: true
四、Mybatis
1、传参问题
1.MyBatis BindingException: Parameter ‘a’ not found(mapper中的参数没有在xml里被使用)
2.解决
这里需要注意的是collection必须为array,否则会报错如下:
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [array]
<select id="selectList" parameterType="java.util.List" resultType="java.lang.Integer">SELECT COUNT(1) FROM t_userWHERE id IN<foreach collection="array" index="index" item="item"open="(" separator="," close=")">#{item}</foreach></select>
2、result问题
MyBatis.TooManyResultsException(封装的返回值不够)
3、异常
java.sql.SQLIntegrityConstraintViolationException(违反完整性约束):
一、其实就是违反了数据库的唯一约束条件!也就是插入数据时,具有唯一约束条件的列值重复了。
根据我图中描述信息的展示可知,我的表中"test1"这一列是具有唯一约束的,现在插入列值时数据有重复了。所以务必确认插入数据的主键或者具有唯一性约束的列不要有重复数据!!!
二、缺少主键
4.sql片段的使用
//<sql>标签和<include>标签的使用
<sql id="selectLfCommodityInfoVo">select id,code,name,value_str,type_code,member_type,category,price,underlined_price,selling_price,type,enable,tax_rate,created,updatedfrom lf_commodity_info</sql><select id="findByCode" resultType="com.xfw.welfare.docking.lf.domain.LfCommodityInfo"><include refid="selectLfCommodityInfoVo"></include>where code=#{code}</select>
5、trim剪切标签的使用
//<trim标签的使用><insert id="insertLfCommodityInfo" parameterType="vip.forwe.model.lf.LfCommodityInfoModel" useGeneratedKeys="true"keyProperty="id">insert into lf_commodity_info<trim prefix="(" suffix=")" suffixOverrides=",">//suffixOverrides后缀覆盖<if test="code != null">code,</if><if test="name != null">name,</if><if test="valueStr != null">value_str,</if><if test="typeCode != null">type_code,</if><if test="memberType != null">member_type,</if><if test="price != null">price,</if><if test="category != null">category,</if><if test="underlinedPrice != null">underlined_price,</if><if test="sellingPrice != null">selling_price,</if><if test="type != null">type,</if><if test="enable != null">enable,</if><if test="created != null">created,</if><if test="updated != null">updated,</if><if test="taxRate != null">tax_rate,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="code != null">#{code},</if><if test="name != null">#{name},</if><if test="valueStr != null">#{valueStr},</if><if test="typeCode != null">#{typeCode},</if><if test="memberType != null">#{memberType},</if><if test="price != null">#{price},</if><if test="category != null">#{category},</if><if test="underlinedPrice != null">#{underlinedPrice},</if><if test="sellingPrice != null">#{sellingPrice},</if><if test="type != null">#{type},</if><if test="enable != null">#{enable},</if><if test="created != null">#{created},</if><if test="updated != null">#{updated},</if><if test="taxRate != null">#{taxRate},</if></trim></insert>//separator分隔符<foreach collection="list" index="index" item="item" separator=",">(#{item.id},#{item.code},#{item.name},#{item.valueStr},#{item.typeCode},#{item.memberType},#{item.category},#{item.price},#{item.underlinedPrice},#{item.sellingPrice},#{item.type},#{item.enable},#{item.taxRate},#{item.created},#{item.updated})</foreach>
五、异常总结
1)数据截断异常
数据截断异常:(原因:导入的数据长度大于数据库长度)
Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation
2)BadSqlGrammarException(只要报这个异常,直接将语句放到数据库调试)
sql语句的问题,1.列名,2.sql语句的异常1.sql列数和参数不一样多
3)result问题
MyBatis.TooManyResultsException(封装的返回值不够)
4)异常
java.sql.SQLIntegrityConstraintViolationException(违反完整性约束):
一、其实就是违反了数据库的唯一约束条件!也就是插入数据时,具有唯一约束条件的列值重复了。
根据我图中描述信息的展示可知,我的表中"test1"这一列是具有唯一约束的,现在插入列值时数据有重复了。所以务必确认插入数据的主键或者具有唯一性约束的列不要有重复数据!!!
二、缺少主键
5)java.lang.IllegalArgumentException: Pattern cannot be null or empty
个人经验,该传的参数没传,参数名称写错了,@requestBody/@requestParam 忘记注解
其他具体问题参考:https://blog.csdn.net/weixin_44259720/article/details/103185972
6)feign.FeignException$NotFound: [404] during [POST]
feign调用失败,当代码确定没用问题的前提下,可能时分布式架构下,多服务启动造成的问题,解决方法在调用方服务中添加被调用方服务名
六、第三方开发工具的使用
1.xshell的使用(linux常用命令行)
https://www.cnblogs.com/bowendown/p/11937159.html 下载安装地址
开发常用命令
tail -200f welfare-operation.nohup.out ()查看具体文件的后几行,查看部署环境下最后发生了什么问题
cd 进入文件
2.xxlJob分布式定时任务的使用
官方文档:https://www.xuxueli.com/xxl-job/
项目结构:
快速入门:
1.建两个分布式事务模块
2.建数据库
3.导入依赖
4.xxlJob配置类(可将配置写入nocas等),必写不然通过代码是不能注册任务的
package com.xfw.welfare.message.config;import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** xxl-job配置* @author xieran*/
@Configuration
@Slf4j
public class XxlJobConfig {@Value("${xxl.job.admin.addresses}")private String adminAddresses;@Value("${xxl.job.accessToken}")private String accessToken;@Value("${xxl.job.executor.appname}")private String appname;@Value("${xxl.job.executor.address}")private String address;@Value("${xxl.job.executor.ip}")private String ip;@Value("${xxl.job.executor.port}")private int port;@Value("${xxl.job.executor.logpath}")private String logPath;@Value("${xxl.job.executor.logretentiondays}")private int logRetentionDays;//执行器组件@Beanpublic XxlJobSpringExecutor xxlJobExecutor() {log.info(">>>>>>>>>>> xxl-job config init.");XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();xxlJobSpringExecutor.setAdminAddresses(adminAddresses);xxlJobSpringExecutor.setAppname(appname);xxlJobSpringExecutor.setAddress(address);xxlJobSpringExecutor.setIp(ip);xxlJobSpringExecutor.setPort(port);xxlJobSpringExecutor.setAccessToken(accessToken);xxlJobSpringExecutor.setLogPath(logPath);xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);return xxlJobSpringExecutor;}}
5.添加并启动任务为例(其实就是调用xxljob的接口)
/****请求xxl-job创建并启动任务接口** @param xxlJobInfo 任务参数 如果 xxlJobInfo.getTriggerStatus == 1 创建的同时并启动任务,xxlJobInfo.getTriggerStatus == 0 只创建任务* @return {@link Integer}* @author xusj* <br>CreateDate 2022/1/21 10:59*///1.XxlJobInfo此参数其实理解上来就是数据库中的XxlJobInfo实体类,实体类见下方
//2.调用addAndStart见下public Integer addAndStart(XxlJobInfo xxlJobInfo) {//发送请求,到xxljobAdmin微服务的controller接口,详细结构见截图HttpsRequest request = new HttpsRequest(addAndStartUrl + "/jobinfo/addAndStart");// 任务参数request.setJsonBody(JSONObject.toJSONString(xxlJobInfo));if (request.executePostRequest()) {String response = request.getResponse();log.info("创建任务:response==={}", response);JSONObject jo = JSON.parseObject(response);if (!"200".equals(jo.getString("code"))) {log.error("创建启动任务失败,jobId={}", xxlJobInfo.getId());throw new RuntimeException(jo.getString("msg"));
// throw new BusinessException(jo.getString("msg"));}return jo.getInteger("content");}throw new RuntimeException("创建任务失败");
// throw new BusinessException("创建任务失败");}
6.实体类(对标数据库中的xxljobinfo表)
package com.xfw.welfare.message.xxljob;import lombok.Data;import java.util.Date;/*** @author xusj* <br>CreateDate 2022/1/21 0:30*/
@Data
public class XxlJobInfo {private int id; // 主键IDprivate int jobGroup; // 执行器主键IDprivate String jobDesc;private Date addTime;private Date updateTime;private String author; // 负责人private String alarmEmail; // 报警邮件private String scheduleType; // 调度类型private String scheduleConf; // 调度配置,值含义取决于调度类型private String misfireStrategy; // 调度过期策略private String executorRouteStrategy; // 执行器路由策略private String executorHandler; // 执行器,任务Handler名称private String executorParam; // 执行器,任务参数private String executorBlockStrategy; // 阻塞处理策略private int executorTimeout; // 任务执行超时时间,单位秒private int executorFailRetryCount; // 失败重试次数private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnumprivate String glueSource; // GLUE源代码private String glueRemark; // GLUE备注private Date glueUpdatetime; // GLUE更新时间private String childJobId; // 子任务ID,多个逗号分隔private int triggerStatus; // 调度状态:0-停止,1-运行private long triggerLastTime; // 上次调度时间private long triggerNextTime; // 下次调度时间private String appName; // 执行器名称
}
7.调用上方5api
//创建并启动任务XxlJobInfo xxlJobInfo = assemblyParam(msgDetRequest);//添加并启用Integer jobId = addAndStartApi.addAndStart(xxlJobInfo);/**** 封装构建job任务参数方法** @param msgDetRequest 消息请求详情* @return {@link XxlJobInfo}* @author xusj* <br>CreateDate 2022/1/21 10:17*/public XxlJobInfo assemblyParam(MsgDetRequest msgDetRequest) {//将时间转化为cron表达式String cron = DateUtil.getCron(msgDetRequest.getDate());//生成jobIdLong jobId = IDGenerator.getId();// jobGroup必须为 ( jobGroup必须为代表的是对应执行器,如果执行器不知道是多少就默认为 0,但是必须传执行器名称appName)XxlJobInfo xxlJobInfo = new XxlJobInfo();xxlJobInfo.setId(jobId.intValue());xxlJobInfo.setJobGroup(0);xxlJobInfo.setAppName("message-executor");xxlJobInfo.setJobDesc("定时推送消息任务" + msgDetRequest.getTitle());xxlJobInfo.setAddTime(new Date());xxlJobInfo.setUpdateTime(new Date());xxlJobInfo.setAuthor("admin");xxlJobInfo.setScheduleType("CRON");xxlJobInfo.setScheduleConf(cron);xxlJobInfo.setMisfireStrategy("DO_NOTHING");xxlJobInfo.setExecutorRouteStrategy("FIRST");//TODO 设置jobHandler名称xxlJobInfo.setExecutorHandler("messageHandler");//TODO 任务参数 消息idxxlJobInfo.setExecutorParam(String.valueOf(msgDetRequest.getMsgId()));xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");xxlJobInfo.setExecutorTimeout(0);xxlJobInfo.setExecutorFailRetryCount(3);xxlJobInfo.setGlueType("BEAN");xxlJobInfo.setGlueRemark("GLUE代码初始化");xxlJobInfo.setGlueUpdatetime(new Date());//TODO 调度状态:0-停止,1-运行 刚添加的调度状态为0(添加定时任务默认为开启)xxlJobInfo.setTriggerStatus(1);xxlJobInfo.setTriggerLastTime(0L);xxlJobInfo.setTriggerNextTime(0L);return xxlJobInfo;}
3.redis使用
https://www.cnblogs.com/yechangzhong-826217795/p/11202316.html
使用安装redis 的坑
Can’t connect to redis-server
解决 运行=》services.msc=》redis启用
4.Jrebel热部署(提高开发效率)
https://www.haah.net/archives/6285.html
七、中间件的使用
1.nacos官方文档
springCloud 引入nocas官方文档 https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
1.下载,
2.导入两个依赖
3.yml书写
server:port: ${APP_PORT:19977}spring:application:name: ${message.namespace:}messagecloud:#重点:寻找nocas中的配置文件nacos:username: ${NACOS_SERVER_USERNAME:nacos}password: ${NACOS_SERVER_PASSWORD:666}server-addr: ${NACOS_SERVER_ADDR:172.16.9.149:666}config:prefix: messageenabled: truefile-extension: ymldiscovery:enabled: trueprofiles:active: devmain:allow-bean-definition-overriding: true
八、开发中Problem
1)spring中使用Junit测试
1、导入Junit依赖
2、注意测试类的路径必需与非测试类路径一样
可参考:https://blog.csdn.net/weixin_39800144/article/details/79241620
注解
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderTest {@Resourceprivate OrderPremiumServiceImpl orderPremiumService;@Resourceprivate BaseInfoMapper baseInfoMapper;@Resourceprivate BaseProductItemsMapper productItemsMapper;// @Test
// public void testCreateOrder(){// CreatOrderRequest request = new CreatOrderRequest();
//
// orderPremiumService.createOrder()
// }/*** 测试,订单信息入库 √*/@Testpublic void testSave() {BaseInfo baseInfo = new BaseInfo();baseInfo.setBaseInfoId(Long.valueOf(10));BaseInfoBuyerContact baseInfoBuyerContact = new BaseInfoBuyerContact();baseInfoBuyerContact.setBuyerId(Long.valueOf(20));BaseInfoSellerContact baseInfoSellerContact = new BaseInfoSellerContact();baseInfoSellerContact.setSellerId(Long.valueOf(30));BaseInfoReceInfo baseInfoReceInfo = new BaseInfoReceInfo();baseInfoReceInfo.setReceInfoId(Long.valueOf(50));BaseInfoLogistics baseInfoLogistics = new BaseInfoLogistics();baseInfoLogistics.setLogId(Long.valueOf(60));BaseInfoLogisticsItems baseInfoLogisticsItems = new BaseInfoLogisticsItems();baseInfoLogisticsItems.setLogItemsId(Long.valueOf(70));BaseProductItems baseProductItems = new BaseProductItems();baseProductItems.setId(Long.valueOf(80));
// orderPremiumService.saveOrder(baseInfo, baseInfoBuyerContact, baseInfoSellerContact, baseInfoReceInfo,
// baseInfoLogistics, baseInfoLogisticsItems, baseProductItems);}
2)代码规范
分new ,get,set(分点组装从参数)
总new ,get,set(将分点组装进总参数)
类中定义方法,代码冗余,地区定义
// 2. 拼接省市区镇街道,调用1688api解析地址编码,调用内部类,并调用内部类中的方法(方法定义在类中)
String districtCode = getDistrictCode(request.getDeliveryAddress().getAddressText());
/** * 地址拼接 * * @return */字符串拼接,使用stringBuilder
public String getAddressText() { StringBuilder text = new StringBuilder(); text.append(provinceText).append(cityText).append(areaText).append(townText).append(address); return text.toString();}
3)分装json对象
//jsonObject 返回json对象(如何封装json对象)
public ArrayList<JSONObject> phoneBill() {ArrayList<JSONObject> result = Lists.newArrayList();List<LfCategory> list = lfCommodityInfoPlMapper.findTypeList(LfType.PHONE_BILL);list.forEach(LfCategory -> {JSONObject category = new JSONObject();category.putOpt("id", LfCategory.getId());category.putOpt("name", LfCategory.getName());category.putOpt("icon", LfCategory.getIcon());category.putOpt("rule", LfCategory.getRules());category.putOpt("specifications", lfCommodityInfoPlMapper.findCommodityListByCategoryId(LfCategory.getId()));int dayOfMonth = DateUtil.thisDayOfMonth();//每月的8-19号 有优惠 其他日期原价category.putOpt("discount", dayOfMonth >= Constant.PHONE_BILL_DISCOUNT_START && dayOfMonth <= Constant.PHONE_BILL_DISCOUNT_END);result.add(category);});return result;}
4)发送Http请求/获取httpRequest和httpResponse
//1,hutool
//发送http请求
HttpResponse response = HttpRequest.post(LFPayGameRequest.URL).form(BeanUtil.beanToMap(request)).timeout(10000).execute();
//2.HttpClient发送
//怎么获得httprequest和httpresponse
public abstract class BaseHandler extends ResponseEntityExceptionHandler {private static ServletRequestAttributes getRequestAttributes() {RequestAttributes attributes = RequestContextHolder.getRequestAttributes();return (ServletRequestAttributes) attributes;
}protected static HttpServletRequest getRequest() {return getRequestAttributes().getRequest();
}protected static HttpServletResponse getResponse() {return getRequestAttributes().getResponse();
}/*** 未知异常*/
@ExceptionHandler(Throwable.class)
@ResponseBody
public Response<?> handleThrowable(Throwable ex) {logger.error("BaseHandler Error", ex);return Response.error(new BusinessException(ErrorMessages.BASIC_0001));
}
}
5)封装对象,
//lf支付请求参数,封装方法
@Data
public class LFPayGameRequest {//定义静态常量public static final String URL = "http://open.jiaofei100.com/Api/PayGame.aspx";private String APIID;private String TradeType;private String Account;private String UnitPrice;private String BuyNum;private String TotalPrice;private String OrderID;private String CreateTime;private String isCallBack;private String GoodsID;private String ClientIP;private String Sign;/*** 生成 sign*///定义类方法public String generateSign(String appKey) {String sb = "APIID=" + APIID +"&Account=" + Account +"&BuyNum=" + BuyNum +"&ClientIP=" + ClientIP +"&CreateTime=" + CreateTime +"&GoodsID=" + GoodsID +"&isCallBack=" + isCallBack +"&OrderID=" + OrderID +"&TotalPrice=" + TotalPrice +"&TradeType=" + TradeType +"&UnitPrice=" + UnitPrice +"&APIKEY=" + appKey;return MD5Util.md5Hex(sb).toUpperCase();}
}
6)BigDecimal类型转化千万不能强制类型转换(精度丢失,详见阿里开发手册),转化(元,分,厘)【无非就是简单的乘除操作】
//BigDecimal
//单位 厘BigDecimal price = infoModel.getUnderlinedPrice().multiply(new BigDecimal("1000")).setScale(0);BigDecimal 分转元BigDecimal feeNo = new BigDecimal(fee);//string 转 BigDecimal 分转元
feeNo = feeNo.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);//分转元
7)String 的正则表达式
fileName.matches("^.+\\.(?i)(xlsx)$")//matches方法
8)pom文件引用的坑,用于抽取API模块时,依赖引用问题
主类中应用api即可,api中不能引用主类中的依赖
9)前后端文件传输
https://blog.csdn.net/sdut406/article/details/85647982 MultipartFile与File的一些事,这两个词一般是Java中出现的吧,前者代表HTML中form data方式上传的文件,后者是文件系统的抽象,前者信息较少,只有二进制数据+文件名称
10)枚举类和属性类的区别
属性类
public class LfType {/*** 类型 : 1.视频 2.游戏 3.话费类 4.卡密*/public final static int VIDEO = 1;public final static int GAME = 2;public final static int PHONE_BILL = 3;public final static int RECHARGE_CARD = 4;}
枚举类
package com.xfw.common.enums;import lombok.Getter;/*** @Classname CodeEnum* @Date 2021/10/19 4:19 下午* @Created by ys*/
@Getter
public enum CodeResponseEnum {PARAMETER_ERROR(10007, "参数错误"),ORDER_TIMEOUT(10008, "订单超时"),PARAMETER_VERIFICATION_ERROR(10009, "参数校验错误"),AGENCY_ID_DOES_NOT_EXIST(10010, "代理商 ID 不存在"),NUMBER_TO_LONG(10011, "订单号长度大于 36"),AGENCY_STATUS_ERROR(10012, "代理商状态错误"),INSUFFICIENT_BALANCE(10013, "账户余额不足"),IP_ERROR(10014, "IP 地址验证失败"),PHONE_ERROR(10015, "充值号码有误"),NOT_SUPPORT(10016, "暂不支持该号码"),BAN(10017, "禁止采购该商品"),SUCCESS(10018, "订单提交成功"),FAILED(10020, "订单提交失败"),UNKNOWN(10021, "未知错误"),DUPLICATE(10022, "订单号重复"),NOT_SUPPORT_01(10024, "暂不支持该面值"),PROCESSING(10025, "订单处理中"),FAIL_TRANSACTION(10026, "交易失败"),SUCCESS_TRANSACTION(10027, "交易成功"),NOT_EXIST(10029, "订单不存在"),LIMIT(10035, "限制5分钟内同一时间和同一个金额"),MAINTENANCE(10036, "系统维护"),NOT_STARTED(10037, "活动未开始"),FINISH(10038, "活动已经结束"),;private final int code;private final String msg;CodeResponseEnum(int code, String msg) {this.code = code;this.msg = msg;}/*** 通过code 获取 enum 对象*/public static CodeResponseEnum getEnum(int code) {CodeResponseEnum result = null;for (CodeResponseEnum s : values()) {//values 表示当前枚举类if (s.getCode() == code) {result = s;break;}}return result;}}
11)list.foreach的实际应用
productCategoryList.forEach(categoryDTO -> {List<ProductCategoryResponse> childCategoryList = productCategoryFactory.getChild(allProductCategoryList,categoryDTO.getId(), getAllCategoryList(), request.getQueryType());if(Objects.nonNull(request.getQueryType()) && request.getQueryType() == 1){//在商品分类界面调用,需要返回商品int productNum = 0;if(CollectionUtils.isEmpty(childCategoryList)){List<Long> categoryIds = new ArrayList<>();ProductCategoryRelWrapper.Selecter matcherSumProductList = new ProductCategoryRelWrapper.Selecter();matcherSumProductList.categoryIdIn(categoryIds);productNum = productCategoryRelMapper.selectCount(matcherSumProductList).intValue();}else {productNum = childCategoryList.stream().mapToInt(ProductCategoryResponse::getProductNum).sum();}categoryDTO.setProductNum(productNum);}categoryDTO.setCategoryChildList(childCategoryList);});
12)巧用三元运算符
/*** 获取限购商品库存,三元运算符*/public int getInventory(String purchaseLimitCode) {String key = getKey(purchaseLimitCode);Integer inventory = (Integer) redisTemplate.opsForValue().get(key);return inventory == null ? 0 : inventory;}
13)Date格式
new DateTime().toString("yyyyMMddHHmmss")//??导入依赖,有问题//java自带Date date = new Date();SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");String s = dateFormat.format(date);System.out.println(s);
14)excel导入导出
取excel的坑 https://blog.csdn.net/qq_35893120/article/details/80395080导出excel模板 https://blog.51cto.com/u_15127658/4337321
15)DTO和VO的区别
http://www.tnblog.net/aojiancc2/article/details/2396
前后端交互使用request和response
VO(View Object):封装参数
视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。
DTO(Data Transfer Object):网络传输,中间件的交互
数据传输对象,泛指用于展示层与服务层之间的数据传输对象。
PO(Persistent Object):
持久化对象,就是和数据库保持一致的对象
16)开发工具安装问题,程序扫描
安装目录空格,查看报错信息,%(符号为百分号),将workspace拉到别的地方
17)配置文件
绑定异常(修改配置文件),我们使用的时Mybatis-plus,实际我们的配置为mybatis,所以配置类读取错误
mybatis-plus:
type-aliases-package: com.xfw.welfare.docking
mapper-locations: classpath*
Java语言是一种解释性的语言,即读一句程序执行一句,这样就需要一 个解释器完成源程序到机器语言的翻译过程.同时Java是跨平台的语 言,跨平台是指Java程序可以在安装任何操作系统的计算机上运行,起 ... 用途说明 ant严格说来,ant其实并非原生的Linux命令,但它是一个使用广泛.功能强大的跨平台构建工具程序,尤其是进行Java开发时,许多开源的Java项目都使用ant作为构建工具.ant命令一般 ... 集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生. 关于HashMap,很多人都对他有一些基本的了解,比如他和hashtab ... 前两天写了一篇关于<阿里Java开发手册中的 1 个bug>的文章,评论区有点炸锅了,基本分为两派,支持老王的和质疑老王的. 首先来说,无论是那一方,我都真诚的感谢你们.特别是「二师兄」, ... 原文:出自本人的Linux博客http://blog.csdn.net/unix21/article/details/18813173 一.Java 开发环境的搭建 这里主要说windows环境下怎么 ... 一.Java 开发环境的搭建 这里主要说windows环境下怎么配置Java环境.如果是Linux环境参考本博客另一篇文章即可: Linux环境安装卸载JDK 1.首先安装JDK java的SDK简称 ... 本节书摘来异步社区<Java 开发从入门到精通>一书中的第2章,第2.2节,作者: 扶松柏 , 陈小玉,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.2 编 ... 初级java开发学习路线 So you have started your journey into the world of web development. But what do you lea ... 想要进入到互联网行业的小伙伴,经常比较纠结学那个学科比较好,目前java.web前端.Python等都是非常热门的行业,前景也是比较好的,选择java学科的人比较多,那么学习java开发的优势是什么呢 ...java开发杂项总结相关推荐
最新文章
热门文章