前言:本人毕业于2021年,刚刚接触java开发,在开发过程中发现自己什么都不懂,因此写下本文作为总结自己在初入开发时遇到的问题,希望有机会看到本文的家人们,避免踩我相同的坑(有些坑自己都觉得傻,本文等于小白成长日志)。本文包括一些java写法,规范,报错问题,常见问题等杂项,希望能帮助各位和我一样刚步入java开发的小伙伴。文中有什么不对的,也希望大家不吝指点。这也是我第一次尝试写博文,一些排版等问题日后也会向大家多多学习。星光不问赶路人 时光不负有心人(本文持续更新)
//使用流过滤
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,但是接收的却是B
list.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 ,但是这里只有List,此时就要想到stream().map
public List<String> queryNamesByIds(List<Long> ids){
List<Category> categories = this.categoryMapper.selectByIdList(ids);
return categories.stream().map(category ->
category.getName()).collect(Collectors.toList());
}
静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
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
}
}
非静态内部类依赖于外部类的实例,也就是说需要先创建外部类实例,才能用这个实例去创建非静态内部类。而静态内部类不需要。
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 context
OuterClass outerClass = new OuterClass();
InnerClass innerClass = outerClass.new InnerClass();
StaticInnerClass staticInnerClass = new StaticInnerClass();
}
}
静态内部类不能访问外部类的非静态的变量和方法。不应该通过类实例访问静态成员,使用类名去访问
父类(静态变量、静态语句块)
子类(静态变量、静态语句块)
父类(实例变量、普通语句块)
父类(构造函数)
子类(实例变量、普通语句块)
子类(构造函数)
add是添加list对象,addAll是添加list中的每一个object
JDK1.8源码中文说明
http://blog.fondme.cn/apidoc/jdk-1.8-google
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帮你做的), 就是自动推导(不是"倒")尖括号里的数据类型.
//转string
Arrays.toString
//判断是否为空
Collections.isEmpty
(1)读文件(输入流):
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("infilename")));
不管你从磁盘读,从网络读,或者从键盘读,读到内存,就是InputStream。
(2)写文件(输出流):
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("outfilename")));
不管你写倒磁盘,写到网络,或者写到屏幕,都是OuputStream
//CollectionUtils,集合工具类 https://blog.csdn.net/huangwenyi1010/article/details/53706297
//交并补差,是否相等,是否为空等等
CollectionUtils.isEmpty(childCategoryList);
//StringUtils,字符工具类
StringUtils.isEmpty();
name like concat(‘%’,#{name},‘%’);
//循环数组,开闭,分隔器
#{id}
/**
trim(剪切的用法)
prefix:在trim标签内sql语句加上前缀。
suffix: 在trim标签内sql语句加上后缀。
suffixOverrides:指定去除多余的后缀内容,如:suffixOverrides=",",去除trim标签内sql语句多余的后缀","。
prefixOverrides: 指定去除多余的前缀内容
**/
insert into lf_commodity_info
code,
name,
value_str,
type_code,
member_type,
price,
category,
underlined_price,
selling_price,
type,
enable,
created,
updated,
tax_rate,
#{code},
#{name},
#{valueStr},
#{typeCode},
#{memberType},
#{price},
#{category},
#{underlinedPrice},
#{sellingPrice},
#{type},
#{enable},
#{created},
#{updated},
#{taxRate},
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,"男")
select icon
from lf_category a
right join lf_commodity_info b on a.type=b.type
where b.category = #{category}
左联接:已一边为主表保留其全部数据
select icon
from lf_category a
where a.type = (select type
from lf_commodity_info b
where b.category = #{category})
//distinct去重查询
select icon
from lf_category a
where a.type = (select DISTINCT type from lf_commodity_info b where b.category = #{category})
//关联查询的去重
SELECT
a.id,
a.title,
a.total,
count( DISTINCT ( b.user_id ) ) AS 'read',//去重后计算该类别中的总数
a.time,
a.status
FROM
message a
RIGHT JOIN msg_read b ON a.id = b.msg_id
GROUP BY a.id//巧用分组,分组计算
(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})
创建应用主类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);
//添加注解,实现api接口
@RestController
public class IfClient implements LfHandleApi {
@Resource
private LfCommodityInfoMapper lfCommodityInfoMapper;
@Resource
private DocLfPayService lfPayService;
@Resource
private LfCategoryMapper lfCategoryMapper;
/***
*在璐付平台进行支付
* @param lfOrderInfo
* @author xusj
*
CreateDate 2022/1/4 10:06
*/
@Override
public 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, "商品类型不存在!");
}
}
@Override
public LfCommodityInfo findByCode(String code) {
//通过code查询
LfCommodityInfo lfCommodityInfo = lfCommodityInfoMapper.findByCode(code);
return lfCommodityInfo;
}
@Override
public 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);
}
三层架构的理解,lfclient,DocLfPayservice,DocLfPayserviceimpl 区别
一、远程调用类再主服务中,实现api中api接口方法(这里写url),需要注解@RestController,类似于实现类
定时任务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);
}
server: //端口
port: ${APP_PORT:19970}
spring:
application:
name: ${order-server.namespace:}order
cloud:
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: order
enabled: true
file-extension: yml
discovery:
enabled: true
profiles:
active: @profiles.active@
main:
allow-bean-definition-overriding: true
1.MyBatis BindingException: Parameter ‘a’ not found(mapper中的参数没有在xml里被使用)
这里需要注意的是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_user
WHERE id IN
<foreach collection="array" index="index" item="item"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
MyBatis.TooManyResultsException(封装的返回值不够)
java.sql.SQLIntegrityConstraintViolationException(违反完整性约束):
一、其实就是违反了数据库的唯一约束条件!也就是插入数据时,具有唯一约束条件的列值重复了。
根据我图中描述信息的展示可知,我的表中"test1"这一列是具有唯一约束的,现在插入列值时数据有重复了。所以务必确认插入数据的主键或者具有唯一性约束的列不要有重复数据!!!
二、缺少主键
//标签和标签的使用
<sql id="selectLfCommodityInfoVo">
select id,
code,
name,
value_str,
type_code,
member_type,
category,
price,
underlined_price,
selling_price,
type,
enable,
tax_rate,
created,
updated
from lf_commodity_info
</sql>
<select id="findByCode" resultType="com.xfw.welfare.docking.lf.domain.LfCommodityInfo">
<include refid="selectLfCommodityInfoVo"></include>
where code=#{code}
</select>
//
<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>
数据截断异常:(原因:导入的数据长度大于数据库长度)
Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation
sql语句的问题,1.列名,2.sql语句的异常1.sql列数和参数不一样多
MyBatis.TooManyResultsException(封装的返回值不够)
java.sql.SQLIntegrityConstraintViolationException(违反完整性约束):
一、其实就是违反了数据库的唯一约束条件!也就是插入数据时,具有唯一约束条件的列值重复了。
根据我图中描述信息的展示可知,我的表中"test1"这一列是具有唯一约束的,现在插入列值时数据有重复了。所以务必确认插入数据的主键或者具有唯一性约束的列不要有重复数据!!!
二、缺少主键
个人经验,该传的参数没传,参数名称写错了,@requestBody/@requestParam 忘记注解
其他具体问题参考:https://blog.csdn.net/weixin_44259720/article/details/103185972
feign调用失败,当代码确定没用问题的前提下,可能时分布式架构下,多服务启动造成的问题,解决方法在调用方服务中添加被调用方服务名
https://www.cnblogs.com/bowendown/p/11937159.html 下载安装地址
开发常用命令
tail -200f welfare-operation.nohup.out ()查看具体文件的后几行,查看部署环境下最后发生了什么问题
cd 进入文件
官方文档: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;
//执行器组件
@Bean
public 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
*
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
*
CreateDate 2022/1/21 0:30
*/
@Data
public class XxlJobInfo {
private int id; // 主键ID
private int jobGroup; // 执行器主键ID
private 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.GlueTypeEnum
private 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
*
CreateDate 2022/1/21 10:17
*/
public XxlJobInfo assemblyParam(MsgDetRequest msgDetRequest) {
//将时间转化为cron表达式
String cron = DateUtil.getCron(msgDetRequest.getDate());
//生成jobId
Long 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 任务参数 消息id
xxlJobInfo.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;
}
https://www.cnblogs.com/yechangzhong-826217795/p/11202316.html
使用安装redis 的坑
解决 运行=》services.msc=》redis启用
https://www.haah.net/archives/6285.html
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:}message
cloud:
#重点:寻找nocas中的配置文件
nacos:
username: ${NACOS_SERVER_USERNAME:nacos}
password: ${NACOS_SERVER_PASSWORD:666}
server-addr: ${NACOS_SERVER_ADDR:172.16.9.149:666}
config:
prefix: message
enabled: true
file-extension: yml
discovery:
enabled: true
profiles:
active: dev
main:
allow-bean-definition-overriding: true
2、注意测试类的路径必需与非测试类路径一样
可参考:https://blog.csdn.net/weixin_39800144/article/details/79241620
注解
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderTest {
@Resource
private OrderPremiumServiceImpl orderPremiumService;
@Resource
private BaseInfoMapper baseInfoMapper;
@Resource
private BaseProductItemsMapper productItemsMapper;
// @Test
// public void testCreateOrder(){
// CreatOrderRequest request = new CreatOrderRequest();
//
// orderPremiumService.createOrder()
// }
/**
* 测试,订单信息入库 √
*/
@Test
public 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);
}
分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();}
//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;
}
//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));
}
}
//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();
}
}
//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);//分转元
fileName.matches("^.+\\.(?i)(xlsx)$")//matches方法
主类中应用api即可,api中不能引用主类中的依赖
https://blog.csdn.net/sdut406/article/details/85647982 MultipartFile与File的一些事,这两个词一般是Java中出现的吧,前者代表HTML中form data方式上传的文件,后者是文件系统的抽象,前者信息较少,只有二进制数据+文件名称
属性类
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;
}
}
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);
});
/**
* 获取限购商品库存,三元运算符
*/
public int getInventory(String purchaseLimitCode) {
String key = getKey(purchaseLimitCode);
Integer inventory = (Integer) redisTemplate.opsForValue().get(key);
return inventory == null ? 0 : inventory;
}
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);
取excel的坑 https://blog.csdn.net/qq_35893120/article/details/80395080
导出excel模板 https://blog.51cto.com/u_15127658/4337321
http://www.tnblog.net/aojiancc2/article/details/2396
前后端交互使用request和response
VO(View Object):封装参数
视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。
DTO(Data Transfer Object):网络传输,中间件的交互
数据传输对象,泛指用于展示层与服务层之间的数据传输对象。
PO(Persistent Object):
持久化对象,就是和数据库保持一致的对象
安装目录空格,查看报错信息,%(符号为百分号),将workspace拉到别的地方
绑定异常(修改配置文件),我们使用的时Mybatis-plus,实际我们的配置为mybatis,所以配置类读取错误
mybatis-plus:
type-aliases-package: com.xfw.welfare.docking
mapper-locations: classpath* */mapper/mapping/ *.xml
接前端参数,或者接远程调用的参数的为null时可能时因为@RequestBody注解忘记打了等注解没使用
转时间格式(在类属性中)
@ApiModelProperty(value = "操作时间,最近一次上下架的时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date operateDate;
package com.xfw.welfare.docking.dto.request;
import cn.modousa.mds.common.tools.MD5Util;
import lombok.Data;
/**
* @author xusj
*
CreateDate 2022/1/4 10:46
*/
@Data
public class LFPayVideoRequest {
public static final String URL = "http://open.jiaofei100.com/Api/PayVideo.aspx";
private String APIID;
private String Account;
private String ProductCode;
private String BuyNum;
private String OrderID;
private String CreateTime;
private String IsCallBack;
private String CallBack;
private String Sign;
/**
* 生成 sign
*/
public String generateSign(String appKey) {
String sb = "APIID=" + APIID +
"&Account=" + Account +
"&BuyNum=" + BuyNum +
"&CreateTime=" + CreateTime +
"&IsCallBack=" + IsCallBack +
"&OrderID=" + OrderID +
"&ProductCode=" + ProductCode +
"&APIKEY=" + appKey;
return MD5Util.md5Hex(sb).toUpperCase();
}
}
private String a;//需要set get方法,new之后get出来
public String b;//可以new之后直接点出来
1.数据库设计 https://github.com/jly8866/archer/blob/master/src/docs/mysql_db_design_guide.md
2.了解mq的使用场景 https://www.zhihu.com/question/34243607
// MultipartFile转inputstream,前后端传文件流,不会传地址,传的是文件流
//例
@PostMapping("/upload")
@ApiOperation("上传文件到oss")
@ApiImplicitParam(name = "pathName", value = "参数,文件地址", required = true, dataType = "MultipartFile")
public Response<String> uploadFile(@RequestParam MultipartFile pathName) throws IOException {
String filename = pathName.getOriginalFilename();//获得流中的文件名
InputStream inputStream = pathName.getInputStream();//将文件流转化为输入流
String url = ossUtil.uploadFile(inputStream,filename);//调用下面的方法
if (!StringUtils.isEmpty(url)) {
return Response.ok(url);
}
log.error("文件上传到Oss失败");
throw new BusinessException(ErrorMessages.BASIC_0001);
}
//oss通过流上传文件
public String uploadFile(InputStream inputStream,String fileName) throws IOException {
//首先判断是否有welfare的存储空间
createBucket();
//将本地文件上传到存储空间bucket中的目录中
//依次填写Bucket名称(例如examplebucket)、Object完整路径(例如exampledir/exampleobject.txt)和本地文件的完整路径。Object完整路径中不能包含Bucket名称。
//TODO bucket下的目录文件夹?
PutObjectRequest objectRequest = new PutObjectRequest(OssConfig.BUCKET_NAME, "common/" + fileName,inputStream);
//上传文件
PutObjectResult putObjectResult = ossClient.putObject(objectRequest);
//判断ETag(ETag用于标识一个Object的内容)
if (StringUtils.isEmpty(putObjectResult.getETag())) {
log.error("上传文件失败{}");
//关闭OssClient
ossClient.shutdown();
return "false";
}
log.info("上传文件成功{}");
//拼接访问url
String url = backUrl(fileName);
//关闭OssClient
ossClient.shutdown();
return url;
}
//示例,多态,没必要强行给fileinputstream,想的不全面,变通一点,在idea中查看java继承体系,ctrl+h
右键,最后一个,show继承体系
// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
//多态
InputStream inputStream = new FileInputStream("D:\\localpath\\examplefile.txt");
除了关联查询不行,基本上都可以操作
@Override
public AlipayOrderInfo findByOutTradeNo(String outTradeNo) {
AlipayOrderInfoWrapper.Selecter matcher = new AlipayOrderInfoWrapper.Selecter();
//通过以上对象进行具体的操作
matcher.outTradeNoEq(outTradeNo);//等于
matcher.orderByDesc(AlipayOrderInfo.cols().id().orderNo().toList());//降序
return alipayOrderInfoMapper.selectOne(matcher);//wrapper入参
}
@Override
public AlipayOrderInfo findByOrderNo(String orderId) {
AlipayOrderInfoWrapper.Selecter matcher = new AlipayOrderInfoWrapper.Selecter();
matcher.orderNoEq(orderId);//等于不同的id,通过点出不同的东西控制
return alipayOrderInfoMapper.selectOne(matcher);//将wrapper入参
}
#### 6.时间戳
//获得13位时间戳精确到毫秒
long date = System.currentTimeMillis();
//阿里开发手册强制推荐:
//1.获取毫秒数,必须使用
System.currentTimeMillis();
//2,而不是
new Date().getTime();
// 配置类写法一
package com.xfw.docking.proxy.config;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* xxl-job配置
*/
@Configuration
public class XxlJobConfig {
private final Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@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;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.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;
}
}
//yml结构
xxl:
job:
admin:
addresses: "ghjhgfhj"
// 配置类写法二
@Configuration
@ConfigurationProperties(prefix = "fulu") //配置中以fulu为前缀的配置
@Data
public class FuluConfigBean {
private String appKey;
private String appSecret;
private String memberCode;
private String memberName;
private String gateway;
private String alipayAccount;
private String alipayAccountName;
private String transferAmount;
private String warningAmount;
}
//yml结构
fulu:
appKey: "ghjkjhg"
......
server:
port: ${APP_PORT:19000}
servlet:
context-path: /
spring:
application:
name: ${xxl-job-admin.namespace:}xxl-job-admin
cloud:
nacos:
username: ${NACOS_SERVER_USERNAME:nacos}
password: ${NACOS_SERVER_PASSWORD:xfw1234}
server-addr: ${NACOS_SERVER_ADDR:172.16.9.159:8848}
config:
prefix: xxl-job //nocos中配置的前缀
enabled: true //启用
file-extension: yml//nocos中配置的后缀
discovery:
enabled: true
profiles:
active: @profiles.active@
main:
allow-bean-definition-overriding: true
spring:
datasource:
url: jdbc:mysql://47.99.39.180:3306/welfare_dev_xxl_job?serverTimezone=CST&useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useInformationSchema=true
username: root
password: xinfengwei,2018
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
connect-properties:
config.decrypt: false
config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKEDoKdvmsSWILeeRuCqu4yjlaPAoKJbrJw1JNoAP20YLZmvC8kl+/bYwLpmog97lO16PELsPMy/ovq5I2fot2cCAwEAAQ==
filter:
config:
enabled: true
xfw:
enabled: true
max-active: 64
initial-size: 10
min-idle: 10
max-wait: 6000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: select 'X'
test-while-idle: true
test-on-borrow: false
test-on-return: false
### xxl-job, access token
xxl:
job:
accessToken: y@Ylv2fOxX07SgYm
### xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en")
i18n: zh_CN
## xxl-job, triggerpool max size
triggerpool:
fast:
max: 200
slow:
max: 100
logretentiondays: 365
redis:
database: 11
host: 47.99.39.180
port: 6379
password: 'xinfengwei,2018'
timeout: 1000
lettuce:
pool:
max-active: 2
max-idle: 2
min-idle: 1
max-wait: -1
servlet:
multipart:
max-file-size : 20MB
max-request-size: 100MB
cloud:
bus:
enabled: false
### xxl-job, log retention days
logretentiondays: 7
environment:
variable: DEV
{
'list':[1,1],//json传集合,数组
"flag":1,
"msgId": **null**,
"title": "测试新建6",
"content": "新建内容6",
"imgUrl": "https://img-bss.csdn.net/1640226649214.png",
"proId": 1,
"push": 1,
"date": "2020-05-01 01:01:09"//json时间格式
}
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")//此注解
private Date created;
//注意返回结果,注意传参
public PageInfo<MsgFrontPage> queryMsgPage(Integer pageNum, Integer pageSize) {
PageHelper.startPage(pageNum, pageSize);//在这里控制就好了
List<MsgFrontPage> messagesList = messageMapper.queryMsg();//还是全查出来
return new PageInfo<>(messagesList);//将查出来的集合进行分页
}
//
int[] ids= Arrays.stream(str.split(",")).mapToInt(s -> Integer.parseInt(s)).toArray();
//转为请求方法对应参数类型
List<Integer> collect = Arrays.stream(ids).boxed().collect(Collectors.toList());
//一个小坑,集合转为字符串之后,每个逗号后还是有空格的,所以在使用split分割的时候需要加空格
//集合转完有空格
long[] longs = Arrays.stream(substring.split(", ")).mapToLong(item -> Long.parseLong(item)).toArray();
集合转数组(阿里开发手册)
【强制】使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一
致、长度为 0 的空数组。
反例:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现
ClassCastException 错误。
正例:
List<String> list = new ArrayList<>(2);
list.add("guan");
list.add("bao");
String[] array = list.toArray(new String[0]);
说明:使用 toArray 带参方法,数组空间大小的 length: 1) 等于 0,动态创建与 size 相同的数组,性能最好。
2) 大于 0 但小于 size,重新创建大小等于 size 的数组,增加 GC 负担。
3) 等于 size,在高并发情况下,数组创建完成之后,size 正在变大的情况下,负面影响与 2 相同。
4) 大于 size,空间浪费,且在 size 处插入 null 值,存在 NPE 隐患。
长整型都是使用string去接收,传long超过16位就会造成精度丢失
servlet:
multipart:
max-file-size: 10MB
max-request-size: 20MB
enabled: true
POM标签大全详解 - Youpeng - 博客园 (cnblogs.com)
//父工程例子
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xfw</groupId>
<artifactId>welfare</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>welfare</name>
<description>描述</description>
//版本号统一管理
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<xfw-framework.version>1.0.15</xfw-framework.version>
<jjwt.version>0.9.1</jjwt.version>
<springboot.version>2.3.8.RELEASE</springboot.version>
<springcloud.version>Hoxton.SR9</springcloud.version>
<aliyun.openservices.version>1.8.8.Final</aliyun.openservices.version>
<spring-cloud-alibaba-dependencies.version>2.2.6.RELEASE</spring-cloud-alibaba-dependencies.version>
<fastjson.version>1.2.66</fastjson.version>
<lombok.version>1.18.16</lombok.version>
<redisson.version>3.8.2</redisson.version>
<mybatisplus.version>3.4.3.2</mybatisplus.version>
<commons-beanutils.version>1.9.4</commons-beanutils.version>
<welfare-version>0.0.1-SNAPSHOT</welfare-version>
<swagger2.version>2.9.2</swagger2.version>
<knife4j.version>2.0.9</knife4j.version>
<swagger-models.version>1.5.22</swagger-models.version>
<dingtalk-sdk.version>2.0.0</dingtalk-sdk.version>
</properties>
//父工程模块的管理子模块工程,与删除添加同步
<modules>
<!--网关-->
<module>welfare-gateway</module>
<!--商品-->
<module>welfare-product</module>
<!--商品对外api-->
<module>welfare-product-api</module>
<!--订单-->
<module>welfare-order</module>
<!--订单对外api-->
<module>welfare-order-api</module>
<!--三方璐付对接-->
<module>welfare-lf</module>
<!--璐付对外api,同代理proxy对接-->
<module>welfare-lf-api</module>
<!--通用-->
<module>welfare-common</module>
<!--代码生成-->
<module>welfare-generator</module>
<!--同步、下单、状态、代理项目,针对实体-->
<module>welfare-docking-proxy</module>
<!--xxl-job主项目-->
<module>xxl-job-admin</module>
<!--xxl-job核心包-->
<module>xxl-job-core</module>
<!--运营端-->
<module>welfare-operation</module>
<!--企业端-->
<module>welfare-enterprise</module>
<!--系统管理-->
<module>welfare-system</module>
<!--系统管理api-->
<module>welfare-system-api</module>
<!--消息模块-->
<module>welfare-message</module>
<!--消息模块api -->
<module>welfare-message-api</module>
<!--鉴权 -->
<module>welfare-authentication</module>
<module>welfare-auth</module>
<module>welfare-auth-api</module>
<module>welfare-push</module>
</modules>
//dependencyManagement:依赖管理,这是父工程需要使用的,有时内部依赖可能会爆红,可以把 dependencyManagement删除重新down依赖即可,然后重新添加标签
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>//引入版本号的格式
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${springcloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.aliyun.openservices</groupId>
<artifactId>ons-client</artifactId>
<version>${aliyun.openservices.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${commons-beanutils.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>${swagger-models.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger-models.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger2.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
//依赖引入
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
//子工程例子
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
//父工程标签
<parent>
<artifactId>welfare</artifactId>
<groupId>com.xfw</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>welfare-message</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<exclusions>
<exclusion>
<artifactId>archaius-core</artifactId>
<groupId>com.netflix.archaius</groupId>
</exclusion>
<exclusion>
<artifactId>HdrHistogram</artifactId>
<groupId>org.hdrhistogram</groupId>
</exclusion>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!-- freemarker-starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>com.xfw</groupId>
<artifactId>welfare-common</artifactId>
<version>${welfare-version}</version>
//去除依赖中的某个依赖
<exclusions>
<exclusion>
<groupId>com.xfw.framework</groupId>
<artifactId>xfw-framework-leopard-auth</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.xfw</groupId>
<artifactId>welfare-authentication</artifactId>
<version>${welfare-version}</version>
</dependency>
<dependency>
<groupId>com.xfw</groupId>
<artifactId>welfare-message-api</artifactId>
<version>${welfare-version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dingtalk</artifactId>
<version>1.2.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.xfw.framework</groupId>
<artifactId>xfw-framework-leopard-dingtalk-base</artifactId>
<version>${xfw-framework.version}</version>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven-central</id>
<name>maven-central</name>
<url>http://47.99.39.180:8781/repository/maven-releases/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<profiles>
<profile>
<!-- 本地开发环境 -->
<id>dev</id>
<properties>
<profiles.active>dev</profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<!-- 测试环境 -->
<id>test</id>
<properties>
<profiles.active>test</profiles.active>
</properties>
</profile>
<profile>
<!-- 生产环境 -->
<id>pro</id>
<properties>
<profiles.active>pro</profiles.active>
</properties>
</profile>
<profile>
<!-- 预发环境 -->
<id>pre</id>
<properties>
<profiles.active>pre</profiles.active>
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources/pre</directory>
</resource>
</resources>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<encoding>UTF-8</encoding>
<nonFilteredFileExtensions>ttf</nonFilteredFileExtensions>
<nonFilteredFileExtensions>pdf</nonFilteredFileExtensions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<configuration>
<tasks>
<copy todir="../target">
<!-- project.build.directory表示各个模块的target目录 -->
<fileset dir="${project.build.directory}">
<!-- 需要复制的jar包文件名称 -->
<include name="${project.artifactId}-${project.version}.jar"/>
</fileset>
</copy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml
false
src/main/resources
**/ *.yml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>fonts/*
src/main/resources
true
test/*
pro/*
pro/*
dev/*
fonts/*
src/main/resources/${profiles.active}
1.详细,清楚
2.有状态接口文档需要枚举(如:有状态1,2,3;需要标明1,2,3的具体意思)
private Map<String, String> advanceBody(Date startTime, String corpId, String subjectName, Long courseId, String courseName, String coursePlanTitle,
String teacherName, Integer classDuration, String role) {
Map<String, String> body = Maps.newHashMap();
body.put("startTime", DateUtil.dateToString(startTime, DateUtil.HH_MM));
body.put("subjectName", subjectName);
body.put("courseName", courseName);
body.put("coursePlanTitle", coursePlanTitle);
body.put("teacherName", teacherName);
body.put("classDuration", classDuration + "");
body.put("title", "【上课提醒】");
// 构造dingtalk链接
body.put("h5Url", getMsgUrl(false, role, corpId, courseId));
body.put("pcUrl", getMsgUrl(true, role, corpId, courseId));
return body;
}
/**
* 拼接data
*
* @param msgType
* @param title
* @param image
* @param content
* @param messageUrl
* @return
*/
public String advanceBody(String msgType, String title, String image, String content, String messageUrl) {
Map<String, String> body = Maps.newHashMap();
body.put("msgType", msgType);
body.put("title", title);
body.put("image", image);
body.put("content", content);
body.put("messageUrl", messageUrl);
return JSON.toJSONString(body);//需要string,就把map转成string,不能硬拼接需要使用map
}
//${agentId}必需以${}的形式存在,占位符
public static void main(String[] args) {
String url="dingtalk://dingtalkclient/action/open_micro_app?corpId=${corpId}&agentId=${agentId}&miniAppId=%s&pVersion=1&packageType=1&page=%2Fpages%2Fgoods%2Fgoods%3FproductsId%3D";
HashMap<Object, Object> map = new HashMap<>();
map.put("corpId",122);
map.put("agentId",1222);
//参数为map,代替字符串中的对应位置,占位符
StrSubstitutor strSubstitutor = new StrSubstitutor(map);
String str = strSubstitutor.replace(url);
System.out.println(str);
}
//sql执行过程 EXPLAIN关键字
EXPLAIN select `id`, `corp_id`, `agent_id`, `suite_id`, `ding_user_id_added`, `create_time`, `update_time`, `auth_status`, `service_status`, `is_delete` from sys_corp_suite GROUP BY corp_id
EXPLAIN select id from sys_corp_suite where id='123456789'
//循环拿出userId
//所要操作的集合
List<SysCorpSuite> userList = sysCorpSuiteApi.findAddUser(item.getCorpId());
//1。lambda表达式
List<String> useridList = userList.stream().map(user -> {
String dingUserId = user.getDingUserIdAdded();
return dingUserId;
}).collect(Collectors.toList());
//2。优化写法
List<String> useridList = userList.stream().map(SysCorpSuite::getDingUserIdAdded).collect(Collectors.toList());
(具体情况具体分析,参考阿里巴巴开发手册)建议使用枚举类 https://blog.csdn.net/chenpeng19910926/article/details/76210117
https://www.jianshu.com/p/dfc3ec4350e6(参考博客) 详见阿里巴巴开发手册
【强制】浮点数之间的等值判断,基本数据类型不能用==来比较,包装数据类型不能用 equals
来判断。
说明:浮点数采用“尾数+阶码”的编码方式,类似于科学计数法的“有效数字+指数”的表示方式。二进
制无法精确表示大部分的十进制小数,具体原理参考《码出高效》。
反例:
float a = 1.0F - 0.9F;
float b = 0.9F - 0.8F;
if (a == b) {
// 预期进入此代码块,执行其它业务逻辑
// 但事实上 a==b 的结果为 false
}
Float x = Float.valueOf(a);
Float y = Float.valueOf(b);
if (x.equals(y)) {
// 预期进入此代码块,执行其它业务逻辑
// 但事实上 equals 的结果为 false
}
正例:
(1) 指定一个误差范围,两个浮点数的差值在此范围之内,则认为是相等的。
float a = 1.0F - 0.9F;
float b = 0.9F - 0.8F;
float diff = 1e-6F;
if (Math.abs(a - b) < diff) {
System.out.println("true");
}
(2) 使用 BigDecimal 来定义值,再进行浮点数的运算操作。
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");
BigDecimal x = a.subtract(b);
BigDecimal y = b.subtract(c);
if (x.compareTo(y) == 0) {
System.out.println("true");
}
尽量使用entrySet ,java8中推荐是红map.forEach((key,value)->{}), 详情参照阿里开发手册
while (iterator.hasNext()) {
String id = iterator.next();
if (!sysUserProductSettingApi.getMsgUserProductSetting(Long.valueOf(id))) {
iterator.remove();
}
}
package com.example.l220109.my;
import org.junit.Test;
/**
* @author xusj
*
CreateDate 2022/2/10 0:41
*/
public class Rucursion {
/**
*
* 迷宫问题求解
*
*/
@Test
public void demo() {
// 构建一个 8 行 7 列的地图
int[][] map = initMap(8, 7);
printMap(map);
// 一次性没有回溯的路线
setWay(map, 1, 1, 6, 5);
// 这个点,是有回溯的路线
// setWay(map, 1, 1, 4, 1);
System.out.println("路线查找完毕");
printMap(map);
}
/**
*
* 思路说明:
* 1. 从 startX,startY 开始走,到 endX,endY 结束
* 2. 当走到 endX,endY 时,表示已经找到了路线
* 3. 约定:map 中的含义:
* 0:表示该点没有走过
* 1:表示围墙,不能走
* 2:表示改点已走过,并且可以走
* 3:表示改点已走过,但是走不通
*
* 4. 走迷宫,约定一个寻找路线的策略,也就是当你站在一个点的时候,你从哪一个方向开始探索?
* 这里规定探索的方向为:下 -> 右 -> 上 -> 左,如果该点走不通,再回溯
*
*
* @param map 代表一张地图
* @param startX 从哪一个点开始走
* @param startY
* @param endX 到哪一个点结束
* @param endY
* @return true: 表示该点可以走,false:表示改点不能走
*/
public boolean setWay(int[][] map, int startX, int startY, int endX, int endY) {
// 如果当结束点已经走过,表示已经到达了出口
// System.out.println();
// printMap(map); // 打开这个可以看到每一步的探索路径
if (map[endX][endY] == 2) {
return true;
}
// 那么开始我们的策略探索
// 如果该点还没有走过,则可以尝试探索
if (map[startX][startY] == 0) {
// 先假定该点标可以通过,因为要去探索四周的点是否可以走
map[startX][startY] = 2;
// 下 -> 右 -> 上 -> 左
// 根据策略:先往下走,如果可以走则返回 true
if (setWay(map, startX + 1, startY, endX, endY)) {
return true;
}
// 如果走不通,则继续往右边探索
else if (setWay(map, startX, startY + 1, endX, endY)) {
return true;
}
// 如果走不通,则继续往上边探索
else if (setWay(map, startX - 1, startY, endX, endY)) {
return true;
}
// 如果走不通,则继续往左边探索
else if (setWay(map, startX, startY - 1, endX, endY)) {
return true;
}
// 都走不通,表示改点是一个死点,四周都无法出去
else {
map[startX][startY] = 3;
return false;
}
} else {
// 如果不为 0,可能的情况是:1,2,3,这三种表示都表示不可以走
return false;
}
}
/**
* 构建一个有挡板的地图
*
* 数字 1:表示挡板围墙,小球不可以经过
* 数字 0:表示是路,小球可以经过
* 起点:可以自定义起点
* 出口:其实也可以自定义出口,但是本题规定,出口就是右下角的 0
* 1 1 1 1 1 1 1
* 1 0 0 0 0 0 1
* 1 0 0 0 0 0 1
* 1 1 1 0 0 0 1
* 1 0 0 0 0 0 1
* 1 0 0 0 0 0 1
* 1 0 0 0 0 0 1
* 1 1 1 1 1 1 1
*
*
* @return
*/
private int[][] initMap(int row, int cloum) {
// 构建一个 8 行 7 列的地图
int[][] map = new int[row][cloum];
// 数字 1 表示挡板,构建一个有挡板的地图
for (int i = 0; i < map[0].length; i++) {
map[0][i] = 1; // 顶部增加挡板
map[map.length - 1][i] = 1; // 底部增加挡板
}
for (int i = 0; i < map.length; i++) {
map[i][0] = 1; // 左侧增加挡板
map[i][map[0].length - 1] = 1; // 右侧增加挡板
}
// 中间的其他固定挡板
map[3][1] = 1;
map[3][2] = 1;
return map;
}
public void printMap(int[][] map) {
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}
/***
* 理解小测试
*
* @param args
* @author xusj
*
CreateDate 2022/2/10 1:10
*/
public static void main(String[] args) {
int i = 7;
// test(7);
test2(7);
}
public static void test(int s) {
// 是递归
if (s > 1) {
test(s - 1);
}
System.out.println(s);
}
public static void test2(int j) {
// 是递归
if (j == 1) {
return;
} else {
test2(j - 1);
System.out.println(j);
}
}
}
类目:类目是一个树状结构的系统,大体上可以分成4-5级。如手机->智能手机->苹果手机类目,在这里面,手机是一级类目,苹果手机是三级类目,也是叶子类目。
SPU:苹果6(商品聚合信息的最小单位),如手机->苹果手机->苹果6,苹果6就是SPU。
SKU:土豪金 16G 苹果6 (商品的不可再分的最小单元)。
从广义上讲,类目>SPU>SKU。
索引与优化like查询
https://juejin.cn/post/6854573219089907720
<select id="getAllRegisterUser"
resultType="cn.org.bjca.econtract.commonbusiness.model.polymerization.dto.UserManagerListDto">
SELECT
a.user_name,
a.mobile,
a.create_time,
b.state
FROM
cb_uc_user_register a
LEFT JOIN cb_uc_user_register_extends b ON a.id = b.user_id
<where>
<if test="userManagerListDto.userName != null and userManagerListDto.userName !=''">
AND a.user_name like concat('%', #{userManagerListDto.userName},'%')
</if>
<if test="userManagerListDto.state != null and userManagerListDto.state != ''">
AND b.state = #{userManagerListDto.state}
</if>
</where>
dingtalk://dingtalkclient/action/open_micro_app?corpId=KaTeX parse error: Expected 'EOF', got '&' at position 9: {corpId}&̲agentId={agentId}&miniAppId=%s&pVersion=1&packageType=1&page=%2Fpages%2Fgoods%2Fgoods%3FproductsId%3D
dingtalk://dingtalkclient/action/open_micro_app?corpId=%s&agentId=%s&miniAppId=%s&pVersion=1&packageType=1&page=%s
https://www.cnblogs.com/BNTang/articles/14584735.html
【强制】对于需要使用超大整数的场景,服务端一律使用 String 字符串类型返回,禁止使用 Long 类型
说明:Java 服务端如果直接返回 Long 整型数据给前端,JS 会自动转换为 Number 类型(注:此类型为双
精度浮点数,表示原理与取值范围等同于 Java 中的 Double)。Long 类型能表示的最大值是 2 的 63 次方
-1,在取值范围之内,超过 2 的 53 次方 (9007199254740992)的数值转化为 JS 的 Number 时,有些数
值会有精度损失。扩展说明,在 Long 取值范围内,任何 2 的指数次整数都是绝对不会存在精度损失的,所
以说精度损失是一个概率问题。若浮点数尾数位与指数位空间不限,则可以精确表示任何整数,但很不幸,
双精度浮点数的尾数位只有 52 位。
反例:通常在订单号或交易号大于等于 16 位,大概率会出现前后端单据不一致的情况,比如,“orderId”:
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}
/***
* 理解小测试
*
* @param args
* @author xusj
*
CreateDate 2022/2/10 1:10
*/
public static void main(String[] args) {
int i = 7;
// test(7);
test2(7);
}
public static void test(int s) {
// 是递归
if (s > 1) {
test(s - 1);
}
System.out.println(s);
}
public static void test2(int j) {
// 是递归
if (j == 1) {
return;
} else {
test2(j - 1);
System.out.println(j);
}
}
}
#### 52)专业词汇类目,spu,sku
类目:类目是一个树状结构的系统,大体上可以分成4-5级。如手机->智能手机->苹果手机类目,在这里面,手机是一级类目,苹果手机是三级类目,也是叶子类目。
SPU:苹果6(商品聚合信息的最小单位),如手机->苹果手机->苹果6,苹果6就是SPU。
SKU:土豪金 16G 苹果6 (商品的不可再分的最小单元)。
从广义上讲,类目>SPU>SKU。
#### 53)sql模糊搜索,索引问题
索引与优化like查询
1. like %keyword 索引失效,使用全表扫描。但可以通过翻转函数+like前模糊查询+建立翻转函数索引=走翻转函数索引,不走全表扫描。
2. like keyword% 索引有效。
3. like %keyword% 索引失效,也无法使用反向索引。
#### 54)说说count(*)、count(1)、count(列名)有什么区别?
https://juejin.cn/post/6854573219089907720
#### 55)xml多条件模糊查询
```java
dingtalk://dingtalkclient/action/open_micro_app?corpId=KaTeX parse error: Expected 'EOF', got '&' at position 9: {corpId}&̲agentId={agentId}&miniAppId=%s&pVersion=1&packageType=1&page=%2Fpages%2Fgoods%2Fgoods%3FproductsId%3D
dingtalk://dingtalkclient/action/open_micro_app?corpId=%s&agentId=%s&miniAppId=%s&pVersion=1&packageType=1&page=%s
https://www.cnblogs.com/BNTang/articles/14584735.html
【强制】对于需要使用超大整数的场景,服务端一律使用 String 字符串类型返回,禁止使用 Long 类型
说明:Java 服务端如果直接返回 Long 整型数据给前端,JS 会自动转换为 Number 类型(注:此类型为双
精度浮点数,表示原理与取值范围等同于 Java 中的 Double)。Long 类型能表示的最大值是 2 的 63 次方
-1,在取值范围之内,超过 2 的 53 次方 (9007199254740992)的数值转化为 JS 的 Number 时,有些数
值会有精度损失。扩展说明,在 Long 取值范围内,任何 2 的指数次整数都是绝对不会存在精度损失的,所
以说精度损失是一个概率问题。若浮点数尾数位与指数位空间不限,则可以精确表示任何整数,但很不幸,
双精度浮点数的尾数位只有 52 位。
反例:通常在订单号或交易号大于等于 16 位,大概率会出现前后端单据不一致的情况,比如,“orderId”:
362909601374617692,前端拿到的值却是: 362909601374617660
MySQL 覆盖索引详解 - 掘金 (juejin.cn)
http://jalan.space/2020/09/01/2020/mysql-using-index/
适用场景:存集合
https://blog.csdn.net/haovip123/article/details/43883109
https://www.cnblogs.com/cy0628/p/15039001.html
sum( CASE WHEN detail.welfare_coin_amount > 0 THEN detail.welfare_coin_amount ELSE 0 END )
userList.parallelStream().map
dingtalk://dingtalkclient/action/open_micro_app?corpId=%s&agentId=%s&miniAppId=5000000002072951&pVersion=1&packageType=1&page=/pages/goods-list/goods-list?id=
dingtalk://dingtalkclient/action/open_micro_app?corpId=dinged57bd8b6ba53cffbc961a6cb783455b&agentId=1447578761&miniAppId=5000000001749662&pVersion=1&packageType=1&page=%2Fpages%2Fgoods-list%2Fgoods-list%3Fid%3D332600646844
//重点:拼接方式:请求方式(get),url地址,参数,超时时间
HttpResponse response = HttpRequest.get(LFPayMobileRequest.PAY_MOBILE_URL).form(BeanUtil.beanToMap(request)).timeout(10000).execute();
流程:
1.在配置文件中配置回调参数(url)
2.写回调接口,供调用接口方进行调用(里面可写一些业务逻辑)
意义:
e.g.1调用支付宝时:支付宝回返回一些参数,需要调用你的接口返回,并且你可以将这些参数入库
e.g.2物流消息的实时更新,也是需要调用回调接口进行操作的
public static boolean isJSON2(String str) {
boolean result = false;//标记使用
try {
Object obj=JSON.parse(str);//fastjson方法,不是的话会抛异常
result = true;
} catch (Exception e) {
result=false;
}
return result;
}
作用:
AssertionError
,只能在开发和测试阶段启用断言解决:controller或者feign对外接口中有多个参数:缺少注解造成:@RequestParam 或者@requestBody
将List转换为JSONArray T为实体类
List<T> list = new ArrayList<T>();
JSONArray array= JSONArray.parseArray(JSON.toJSONString(list));
JSONArray转List RequestDTO为实体类
JSONArray array = new JSONArray();
List<RequestDTO> list = JSONObject.parseArray(array.toJSONString(), RequestDTO.class);
字符串转List T为实体类
String str = ""; 或 String str = "[{T},{T}]"
List<T> list = JSONObject.parseArray(str,T.class);
c.full_name like concat('%',#{name},'%')
package com.xfw.welfare.order.response;
import com.xfw.welfare.order.request.AfterSalesRequest;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
*
CreateDate 2022/2/28 10:44
*/
//返回封装类
@Data
public class OperationAfterSalesResponse {
private String orderNo;
private String applyCreateTime;
private String status;
//一对多定义一个类里面有集合(将数据封装到集合中)
private List<AfterSalesGoods> afterSalesList;
//内部类
@Data
@ApiModel("售后关联商品")
public static class AfterSalesGoods {
@ApiModelProperty(value = "主键")
private String id;
@ApiModelProperty(value = "订单编号")
private String orderNo;
@ApiModelProperty(value = "供货商订单号")
private String providerOrderNo;
@ApiModelProperty(value = "商品名称")
private String goodName;
@ApiModelProperty(value = "商品主图")
private String goodImage;
@ApiModelProperty(value = "规格")
private String goodSkuName;
}
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xfw.welfare.order.mapper.XflAfterSalesMapper">
//1.封装一个返回结果集()在xml中
<resultMap id="baseMap" type="com.xfw.welfare.order.response.OperationAfterSalesResponse">
<result column="order_no" jdbcType="VARCHAR" property="orderNo"/>
<result column="apply_create_time" javaType="String" property="applyCreateTime"/>
<result column="status" javaType="String" property="status"/>
// 2.collection标签的使用位置 ofType中$符号表示内部类(如果是其他的类使用具体的包路径)
// select另一个查询方法
// column条件:这个是第一个查询出来的结果列名和第二个查询中的列关系
<collection property="afterSalesList"
ofType="com.xfw.welfare.order.response.OperationAfterSalesResponse$AfterSalesGoods"
select="com.xfw.welfare.order.mapper.OrderGoodsMapper.selectGoodsByOrderNo"
column="{orderNo = order_no}"/>
resultMap>
#重点列名
<select id="selectByCondition" resultMap="baseMap">
SELECT a.order_no,
a.apply_create_time,
b.irrigation_ditch AS irrigationDitch,
b.good_name AS goodsName,
b.good_sku_name AS goodSkuName,
c.full_name AS buyerName,
c.mobile AS buyerPhone,
a.refund_amount AS amount,
a.`status` AS `status`,
a.`count` AS `count`
FROM xfl_after_sales AS a
LEFT JOIN order_goods AS b ON a.order_no = b.order_no
LEFT JOIN order_info AS c ON a.order_no = c.order_no
<where>
<if test="proName!=null and proName!=''">
and b.good_name like concat('%',#{proName},'%')
if>
<if test="orderNo!=null and orderNo!=''">
and a.order_no=#{orderNo}
if>
<if test="name!=null and name!=''">
and c.full_name like concat('%',#{name},'%')
if>
<if test="channelId!=null and channelId!=''">
and b.irrigation_ditch=#{channelId}
if>
<if test="status!=null and status!=''">
and a.status=#{status}
if>
<if test="phone!=null and phone!=''">
and c.mobile=#{phone}
if>
where>
select>
mapper>
订单状态 1.待付款 2待发货 3.已发货 4已完成 5.已退款 6.已关闭 10.售后中 12.下单中
----------更新2022.03.06
1.通过ER图理清业务实体间的关系(一对一、一对多、多对多)
2.巧用冗余字段(冗余字段:比如在影院评论表中需要查看用户信息=》需要使用userid去关联user表=》但是你需要查出userName=》可以将userName冗余在评论表中=》打破第三范式来增加查询效率【原因就是:在分布式环境中不应该为了某一个字段去远程调用别的接口,提高查询效率】)
3.巧用区分字段:比如有大小图在其中,用type去区别大小图;在省市县三级联动中可以将地名设计在一张表中,但是需要使用区分字段去判断是哪一级别(0:国家 1:省 2:市 3:县)
4.将不会轻易去变动的数据,单存放一张表,然后使用其id去放到其他的表中去关联(比如电影类型不会变动)
5.对于判断类型的业务添加字段来记录(比如定时发送和立即发送)
首先前后端在交互的时候通过一个指定的字段来判断是定时还是立即,当存入数据库的时候,也可以考虑添加该字段;同时这种操作型功能最好加上create_time和update_time
在Jenkens的界面的控制台输出
long是长整型,不能有小数,可以转bigdecimal
String time = "2020-02-13 16:01:30";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try { date = sdf.parse(time); } catch (ParseException e) { e.printStackTrace(); }
xflAfterSalesList.parallelStream().forEach //当数据 过大时开内部线程去跑,提高效率
select IFNULL(SUM(IF((op.`status` is NOT NULL), 1, 0)), 0) as `all`,
IFNULL(SUM(IF((op.`status` = 1), 1, 0)), 0) as waitSeller,
IFNULL(SUM(IF((op.`status` = 2), 1, 0)), 0) as waitBuyer,
IFNULL(SUM(IF((op.`status` = 3), 1, 0)), 0) as waitSellerReceive,
IFNULL(SUM(IF((op.`status` = 6), 1, 0)), 0) as fail
from `xfl_after_sales` op
1.定义一个java类使用List集合来接对应的类
2.主要的时xml的写法(resultMap)
<select id="queryOrderDetail" resultMap="BaseMap">
select order_no //查询出的值对应下面的collection标签中的 column="{orderNo =order_no}"
from `order_info`
where del_tag = 0
and order_no = #{orderNo}
<if test="irrigationDitch != null and irrigationDitch != ''">
and irrigation_ditch = #{irrigationDitch}
if>
select>
<resultMap id="BaseMap" type="com.xfw.welfare.order.response.OrderResponse">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="order_no" jdbcType="VARCHAR" property="orderNo"/>
<result column="order_time" jdbcType="TIMESTAMP" property="orderTime"/>
<result column="remark" jdbcType="VARCHAR" property="remark"/>
// 见上面的解释
<collection property="orderDeliveryResponse" ofType="com.xfw.welfare.order.response.OrderDeliveryResponse"
select="com.xfw.welfare.order.mapper.OrderDeliveryMapper.selectDeliveryByOrderNo"
column="{orderNo = order_no}"/>
resultMap>
servlet:
multipart:
max-file-size: 10MB
max-request-size: 20MB
enabled: true
启动项所在的位置不对,导致扫描不到对应的位置
调用方和被调用方的启动类最好在同一个根目录下
异常:com.mysql.jdbc.MysqlDataTruncation: Data truncation: Incorrect datetime value: ‘1994’ for column ‘reviewTime’ at row 1
事例:
xxljob中param不能方json等太长的,报数据截断(原因数据库的字段长度没有那么值不够大)=》解决方法1。加大字段的长度,2.思考换别的值在该字段中
事例:需求:
定时发送和立刻发送:我刚开始判断传的时间是否为空;实际最优的方法前端添加一个字段,后端通过该字段判断
string.substring(string.lastIndexOf(".") + 1); //最后一个符号的后一位
string.substring(0, string.lastIndexOf(".")); // 从第一个到该符号
public String upload(@RequestParam("multipartFiles") List<MultipartFile> multipartFiles) {
将流放到list中防止多张图片接口调用的过快产生的问题
---------更新2022.03.13
1.文件中最好不要有中文
2.文件最好有唯一便是标识:如在文件中拼接上uuid等,拼接在文件名前面
select max(id)
select max(time)
<insert id="importList" parameterType="java.util.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,
channel)
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},
#{item.channel}
)
foreach>
insert>
<resultMap id="baseMap" type="com.xfw.welfare.order.response.OperationAfterSalesResponse">
<result column="order_no" jdbcType="VARCHAR" property="orderNo"/>
<--column:和查询中的返回值(如果as别名就使用别名)相同;jdbcType:sql字段类;property:java属性名-->
<result column="applyCreateTime" jdbcType="VARCHAR" property="applyCreateTime"/>
<result column="status" javaType="String" property="status"/>
<--javaType:java数据类型-->
<result column="buyerName" javaType="String" property="buyerName"/>
<result column="buyerPhone" javaType="String" property="buyerPhone"/>
<collection property="afterSalesList"
ofType="com.xfw.welfare.order.response.OperationAfterSalesResponse$AfterSalesGoods"
select="com.xfw.welfare.order.mapper.OrderGoodsMapper.selectAfterSalesByOrderNo"
column="{orderNo = order_no}"/>
resultMap>
select max(id),name from stu2
group by name
ORDER BY id //可要可不要,看业务需求
@ApiModelProperty(value = "申请时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")// 注解统一时间格式
private Date applyCreateTime;
Calendar calendar=Calendar.getInstance();
calendar.set(2015, 10, 12); //年月日 也可以具体到时分秒如calendar.set(2015, 10, 12,11,32,52);
Date date=calendar.getTime();//date就是你需要的时间
System.out.println(date.toString());
// 某些请求API,post请求时需要在body中封装参数,参数怎么放
private Map<String, String> advanceBody(Date startTime, String corpId, String subjectName, Long courseId, String courseName, String coursePlanTitle,
String teacherName, Integer classDuration, String role) {
Map<String, String> body = Maps.newHashMap();
body.put("startTime", DateUtil.dateToString(startTime, DateUtil.HH_MM));
body.put("subjectName", subjectName);
body.put("courseName", courseName);
body.put("coursePlanTitle", coursePlanTitle);
body.put("teacherName", teacherName);
body.put("classDuration", classDuration + "");
body.put("title", "【上课提醒】");
// 构造dingtalk链接
body.put("h5Url", getMsgUrl(false, role, corpId, courseId));
body.put("pcUrl", getMsgUrl(true, role, corpId, courseId));
return body;
}
======》更新2022.03.20 01:12(更新内容,数据库设计,请求体参数封装,@jsonFormat,sql查最大,mybatis映射返回类,mybatis集合插入)
// 获取请求头参数 注解@RequestHeader("Authorization")
public Response getUserDetail(@RequestHeader("Authorization") @ApiParam(value = "校验密钥", required = true) String authorization,
<configuration>
<property name="log.path" value="D:/devprogram/idea/workspace/concurrenttest/test02/src/main/resources" />
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}pattern>
encoder>
appender>
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>60maxHistory>
rollingPolicy>
<encoder>
<pattern>${log.pattern}pattern>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFOlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>60maxHistory>
rollingPolicy>
<encoder>
<pattern>${log.pattern}pattern>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERRORlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-user.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>60maxHistory>
rollingPolicy>
<encoder>
<pattern>${log.pattern}pattern>
encoder>
appender>
<logger name="com.xusj" level="info" />
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
root>
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
root>
<logger name="sys-user" level="info">
<appender-ref ref="sys-user"/>
logger>
configuration>
Spring Boot 默认支持 properties(.properties) 和 YAML(.yml .yaml ) 两种格式的配置文件,yml 和 properties 文件都属于配置文件,功能一样。
Spring Cloud 构建于 Spring Boot 之上,在 Spring Boot 中有两种上下文,一种是 bootstrap,另外一种是 application,下面列举这两种配置文件的区别
若application.yml 和bootstrap.yml 在同一目录下:bootstrap.yml 先加载 application.yml后加载
bootstrap.yml 用于应用程序上下文的引导阶段。bootstrap.yml 由父Spring ApplicationContext加载。
bootstrap.yml 和 application.yml 都可以用来配置参数。
bootstrap.yml 用来程序引导时执行,应用于更加早期配置信息读取。可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。一旦bootStrap.yml 被加载,则内容不会被覆盖。
application.yml 可以用来定义应用级别的, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
启动上下文时,Spring Cloud 会创建一个 Bootstrap Context,作为 Spring 应用的 Application Context 的父上下文。
初始化的时候,Bootstrap Context 负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的 Environment。Bootstrap 属性有高优先级,默认情况下,它们不会被本地配置覆盖。
也就是说如果加载的 application.yml 的内容标签与 bootstrap 的标签一致,application 也不会覆盖 bootstrap,而 application.yml 里面的内容可以动态替换。
两个时间段,判断是否有交集。
找到两个时间段开始时间的最大值和结束时间的最小值。
如果开始时间的最大值小于等于结束时间的最小值则说明这两个时间段有交集。
/***
*
* @param startDateOne 第一个时间段的开始时间
* @param endDateOne 第一个时间段的结束时间
* @param startDateTwo 第二个时间段的开始时间
* @param endDateTwo 第二个时间段的结束时间
* @return
*/
public static Boolean IsInterSection(Date startDateOne,Date endDateOne,Date startDateTwo,Date endDateTwo)
{
Date maxStartDate = startDateOne;
if(maxStartDate.before(startDateTwo))
{
maxStartDate = startDateTwo;
}
Date minEndDate = endDateOne;
if(endDateTwo.before(minEndDate))
{
minEndDate = endDateTwo;
}
if(maxStartDate.before(minEndDate) || (maxStartDate.getTime() == minEndDate.getTime()))
{
return true;
}
else {
return false;
}
}
Calendar calendar = Calendar.getInstance();
calendar.set(2099, Calendar.NOVEMBER, 12,10,10,10);
Date date = calendar.getTime();
简单的说,如果有多个文件时,classpath* 前缀再加上通配符,会搜到所有符合的文件;而classpath前缀再加上通配符则可能会在找到一个符合的之后不再查找。
所以使用classpath* 总是没错的。
mybatis:
configuration:
map-underscore-to-camel-case: true
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations:
- classpath:mappers/*.xml
mybatis-plus:
type-aliases-package: com.xfw.welfare.docking
mapper-locations: classpath*:**/mapper/mapping/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
gateway:
routes:
- id: operation
uri: lb://${operation.namespace:}operation
predicates:
- Path=/api/v1/**
filters:
- StripPrefix=2
- PreserveHostHeader #发送网关原始主机头
- id: enterprise
uri: lb://${enterprise.namespace:}enterprise
predicates:
- Path=/api/v1/**
filters:
- StripPrefix=2
- PreserveHostHeader #发送网关原始主机头
zuul:
routes:
service: /a/** 服务名:地址
@RequestParam(value = "endTime", required = false) @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date endTime
// 1、导入依赖
<!--junit测试集成spring-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
// 2、测试包(与项目包同名,不然会有错)
// 3、建工程(注意添加的注解)
package com.xusj.test;
import com.xusj.test.entity.Msg;
import com.xusj.test.service.MsgService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.util.List;
/**
* @author xusj
*
CreateDate 2022/3/24 9:58
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class test {
@Resource
private MsgService msgService;
@Test
public void test01(){
List<Msg> msgs = msgService.selectAll();
for (Msg msg : msgs) {
System.out.println(msg);
}
}
}
有一个地方多了注解@Resource,或者写反了
//string转int,有时候可能会太长,可以先使用long转,在用math方法弄
xxlJobInfo.setId(Math.toIntExact(Long.valueOf(jobId)))
===》2022.03.28(更新:logback,精度,注入异常、又见junit、配置文件区别、网关的使用)
比如debug到当前行数出错,那就先看这一行的原因,在已宏观的方法去看问题
注解@JsonFormat主要是后台到前台的时间格式的转换
注解@DataTimeFormat主要是前后到后台的时间格式的转换
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date symendtime;
集合判空使用collectionUtils
字符串判空使用StringUtils
使用mybatis中批量修改,和map查询调用一次数据库连接即可
@Data
public class MovieVo extends Movie {
// 一对一
private String movieAreaStr;
// 一对多
private List<MovieType> movieTypeList;
//一对多
private List<MovieImage> movieImageList;
}
<resultMap type="com.xusj.cinema.vo.MovieVo" id="MovieVoResult">
<result property="movieId" column="movie_id" />
<result property="movieName" column="movie_name" />
<result property="movieReleaseTime" column="movie_release_time" />
<result property="movieArea" column="movie_area" />
<result property="movieInfo" column="movie_info" />
<result property="movieVersion" column="movie_version" />
<result property="movieImg" column="movie_img" />
<result property="movieEname" column="movie_ename" />
<result property="movieScore" column="movie_score" />
<result property="movieStatus" column="movie_status" />
<result property="movieCount" column="movie_count" />
<result property="movieBoxOffice" column="movie_box_office" />
<result property="movieTime" column="movie_time" />
<result property="movieWantCount" column="movie_want_count" />
<result property="movieReleaseYear" column="movie_release_year" />
<result property="commentUserCount" column="comment_user_count" />
<association property="movieAreaStr" column="movie_area" select="com.xusj.cinema.mapper.MovieAreaMapper.selectMovieAreaByAreaId">association>
<collection property="movieTypeList" ofType="com.xusj.cinema.domain.MovieType" column="movie_id"
select="com.xusj.cinema.mapper.MovieTypeMapper.selectMovieTypeByMovieId">collection>
resultMap>
<select id="queryAllMovies" resultMap="MovieVoResult">
<include refid="selectMovieVo"/>
select>
图解一对一和一对多写法(在绿标处column处不需要列名相同,只是为了拿到查询结果中该列的值去关联查询)
===》2022.04.10(更新:开发注意事项,mybatis一对多和多对多查询总结)
创建一个包名和类名都相同的类
我遇到的情况,sdk中封装问题导致这个类需要覆写。
===》2022.4.17
Linux命令行,定位日志
cat 服务名|grep 需要定位的日志内容
场景:我在处理大数据量的时候,对每一页数据分配一个线程区处理,导致数据一直丢失或者对不上,经过排查发现,没加排序,导致每页查出来的数据不是固定的,所以有的数据丢失了。加上排序即可。
在业务中分页查询其实也是一样的道理,一直会变数据,这里也要加上排序。
小白等于入门中能完成crud该篇,博文停更;接下来持续输出