1.开发更新订单状态的功能

1.1订单的状态码

我们电商上面订单的状态修改是非常普通的业务

随着商品的购买流程,订单的状态有

状态:

0=未支付

1=已关闭(超时未支付)

2=已取消

3=已支付

4=已签收

5=已拒收

6=退款处理中

7=已退款

1.2开发更新订单状态的持久层

修改订单状态就是根据订单id修改订单的state

我们随着业务的发展,订单可能需要更多修改的需求

订单的列(字段)比较多,如果每个字段修改,都需要编写一个方法的话,那么方法的数量会非常多

如果我们编写一个方法,能够接收订单对象的实体类参数(OmsOrder)

我们要实现可以根据OmsOrder对象的实际数据来实现动态的修改要修改的字段

Mybatis中可以通过编写动态修改sql语句完成这个需求

OmsOrderMapper接口添加方法

// 动态修改订单的sql,参数是omsOrder实体类对象
// 对象中必须有id,id不可修改,其它属性不为空就修改其它属性值
int updateOrderById(OmsOrder order);

OmsOrderMapper.xml编写sql

<!--动态修改订单的sql,参数是omsOrder实体类对象对象中必须有id,id不可修改,其它属性不为空就修改其它属性值-->
<!--omsOrder对象除id外的某个属性有值时,下面的动态sql语句,就有通过判断,来生成修改对应列的代码-->
<!--Mybatis框架动态sql标签<set>效果如下1.在<set>标签的位置生成一个set关键字2.在<set></set>标签的范围内,动态生成的sql语句,如果最后一个字符是","就删除它-->
<update id="updateOrderById">update oms_order<set><if test="contactName!=null">contact_name=#{contactName},</if><if test="mobilePhone!=null">mobile_phone=#{mobilePhone},</if><if test="telephone!=null">telephone=#{telephone},</if><if test="streetCode!=null">street_code=#{streetCode},</if><if test="streetName!=null">street_name=#{streetName},</if><if test="detailedAddress!=null">detailed_address=#{detailedAddress},</if><if test="tag!=null">tag=#{tag},</if><if test="paymentType!=null">payment_type=#{paymentType},</if><if test="state!=null">state=#{state},</if><if test="rewardPoint!=null">reward_point=#{rewardPoint},</if><if test="amountOfOriginalPrice!=null">amount_of_original_price=#{amountOfOriginalPrice},</if><if test="amountOfFreight!=null">amount_of_freight=#{amountOfFreight},</if><if test="amountOfDiscount!=null">amount_of_discount=#{amountOfDiscount},</if><if test="amountOfActualPay!=null">amount_of_actual_pay=#{amountOfActualPay},</if><if test="gmtPay!=null">gmt_pay=#{gmtPay},</if></set>whereid=#{id}
</update>

1.3开发修改订单状态的业务逻辑层

OmsOrderServiceImpl

// 根据订单id 修改订单状态的业务逻辑层方法
@Override
public void updateOrderState(OrderStateUpdateDTO orderStateUpdateDTO) {// 参数OrderStateUpdateDTO包含订单id和要修改的状态码// 将参数属性值赋值给OmsOrder类型对象,以便持久层调用OmsOrder order=new OmsOrder();BeanUtils.copyProperties(orderStateUpdateDTO,order);// 调用持久层方法omsOrderMapper.updateOrderById(order);
}

启动Nacos\Seata

启动Order

测试时根据实际数据库订单id,修改knife4j的数据然后再运行

运行后查看数据库中订单状态列是否修改

2.搜索功能

2.1Elasticsearch加载数据

我们要想完成高效的搜索任务,需要ES的支持

因为数据库的模糊查询效率太低了

我们在前端页面中完成的搜索是从ES中搜索数据

这样就要求,我们在查询之前,需要先将商品信息(spu)保存到ES中

一开始我们使用最原始的办法:从数据库查询出数据之后新增到ES中

2.2确认实体类

搜索功能编写在mall-search模块中

它使用的实体类在cn.tedu.mall.pojo.search.eneity包下SpuForElastic

这个类有四个字段是具备分词功能的

所以支持我们使用这4个字段进行查询

/*** SPU名称*/
@Field(name = "name",type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
@ApiModelProperty(value="SPU名称")
private String name;//...../*** 标题*/
@Field(name="title",type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
@ApiModelProperty(value="标题")
private String title;/*** 简介*/
@Field(name="description",type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
@ApiModelProperty(value="简介")
private String description;//...../*** 类别名称(冗余)*/
@Field(name="category_name",type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
@ApiModelProperty(value="类别名称(冗余)")
private String categoryName;//.....

2.3开发ES的持久层

我们仍然使用SpringDataElasticsearch框架来操作ES

按照SpringData的规范,我们创建包repository

在这个包中创建SpuForElasticRepository接口,代码如下

// SpuForElastic实体类操作ES的持久层接口
// 一定要继承父接口,才能具备SpringData提供的基本增删改查功能
@Repository
public interface SpuForElasticRepository extendsElasticsearchRepository<SpuForElastic,Long> {
}

这个接口提供了批量新增到ES数据的方法

但是要想获得数据库中的所有pms_spu表的数据,必须连接数据库查询这些数据

但是search模块是负责管理ES的,所以需要Dubbo调用Product模块获取所有数据

2.4product模块提供的查询功能

我们需要使用Dubbo调用product的业务逻辑层获得数据库pms_spu表的数据

经过观察发现业务逻辑逻辑层调用ForFrontSpuServiceImpl类中

具有一个getSpuByPage的方法

他分页查询所有spu信息

@Override
public JsonPage<Spu> getSpuByPage(Integer pageNum, Integer pageSize) {PageHelper.startPage(pageNum,pageSize);List<Spu> list=spuMapper.findAllList();return JsonPage.restPage(new PageInfo<>(list));
}

分页的原因是因为一般加载到ES中的数据量非常大(几十万上百万条),

我们不可能一次性将所有数据查询出来,增到ES中,必须分批分次

分页查询就是典型的分批查询,每次查询一部分数据,通过循环遍历,将每页数据都新增到ES中

2.5Search模块执行加载

mall-search-webapi模块创建service.impl包

包中创建SearchServiceImpl类,用于将数据库中的数据加载到ES中

代码如下

@Service
@Slf4j
public class SearchServiceImpl implements ISearchService {// dubbo调用product模块查询所有spu@DubboReferenceprivate IForFrontSpuService dubboSpuService;// 将查询出的spu对象新增到ES中@Autowiredprivate SpuForElasticRepository spuRepository;// 先循环调用dubbo分页查询数据库// 将分页查询出的spu对象新增到ES@Overridepublic void loadSpuByPage() {// 我们并不知道本次分页从查询的总页数// 所以是典型的先执行后判断,推荐使用do-whileint i=1;      // 循环次数,从1开始,同时代表页码int pages=0;  // 总页数,在第一次运行之后才能知道具体值,默认值赋0即可(不赋值也可以)do{// dubbo 分页查询页码指定的数据JsonPage<Spu> spus=dubboSpuService.getSpuByPage(i,2);// 需要将JsonPage类型中的数据转换为List<SpuForElastic>,以便新增到ESList<SpuForElastic> esSpus=new ArrayList<>();// 遍历spus,进行转换并新增到esSpusfor(Spu spu : spus.getList()){SpuForElastic esSpu=new SpuForElastic();BeanUtils.copyProperties(spu,esSpu);// 将赋值好的esSpu添加到esSpus中esSpus.add(esSpu);}// esSpus集合中已经添加了当前页数据,执行新增到ESspuRepository.saveAll(esSpus);log.info("成功加载第{}页数据",i);// 为下次循环准备i++;pages=spus.getTotalPage();}while(i<=pages);}@Overridepublic JsonPage<SpuForElastic> search(String keyword, Integer page, Integer pageSize) {return null;}
}

创建测试类

@SpringBootTest
public class LoadTest {@Autowiredprivate ISearchService searchService;@Testvoid loadData(){searchService.loadSpuByPage();System.out.println("ok");}}

运行测试前保证

Nacos\Seata\\ES启动

启动product模块

运行测试,没有报错即可

2.6验证ES中的数据

我们再通过连接ES来进行全查

检验上面执行的加载工作是否达到效果

仍然在测试类中,在编写一个方法,使用SpringData提供的全查方法查询后遍历输出

检查输出内容,代码如下

@Autowired
private SpuForElasticRepository repository;
@Test
void showData(){Iterable<SpuForElastic> spus=repository.findAll();spus.forEach(spu -> System.out.println(spu));
}

2.7搜索功能的实现

电商网站一定会有按用户输入的关键字进行搜索的功能

这样的搜索都是搜索ES查询到的结果

上面章节中,我们已经将所有spu信息保存到了ES中

下面通过查询逻辑将搜索结果显示出来

2.7.1编写SpringData自定义查询

如果我们按照关键字"手机"进行搜索

可以在Repository接口中编写自定义方法

@Repository
public interface SpuForElasticRepository extendsElasticsearchRepository<SpuForElastic,Long> {// 查询title字段包含指定关键字的spu数据Iterable<SpuForElastic> querySpuForElasticsByTitleMatches(String title);}

上面的查询可以通过测试类测试

// 根据title查询数据
@Test
void getSpuByTitle(){Iterable<SpuForElastic> it=repository.querySpuForElasticsByTitleMatches("手机");it.forEach(e -> System.out.println(e));
}

尤其需要关注ES是否已经启动

不需要其它项目的支持,直接运行测试即可

我们业务中需要4个字段的条件查询

SpringData也支持我们在代码中编写查询语句,一避免过长的方法名

@Query("{\n" +"    \"bool\": {\n" +"      \"should\": [\n" +"        { \"match\": { \"name\": \"?0\"}},\n" +"        { \"match\": { \"title\": \"?0\"}},\n" +"        { \"match\": { \"description\": \"?0\"}},\n" +"        { \"match\": { \"category_name\": \"?0\"}}\n" +"        ]\n" +"     }\n" +"}")
// 上面指定了查询语句,这个方法的方法名就随意定义了
Iterable<SpuForElastic> querySearch(String keyword);

测试代码

// 根据title查询数据@Testvoid getSpuByTitle(){
//        Iterable<SpuForElastic> it=
//                repository.querySpuForElasticsByTitleMatches("手机华为小米");Iterable<SpuForElastic> it=repository.querySearch("手机");it.forEach(e -> System.out.println(e));}

在实际开发中

我们数据库中的数据和Elasticsearch中的数据还存在同步问题

为了保持数据库中的数据和Elasticsearch中的数据一致

我们可以使用下面的办法

1.在所有对spu表进行增删改的操作代码运行后,也对ES中的数据进行相同的操作

​ 但是会有比较多的代码要编写,而且有比较明显的事务处理问题

2.实际上业界使用Elasticsearch有一个组合叫ELK,其中L(logstash)可以实现自动同步数据库和ES的信息

后面学习过程中,我们会在Linux虚拟机的学习中使用它

实际运行查询的逻辑是需要分页的

所以要按照SpringData支持的分页查询格式修改上面的查询代码

@Query("{\n" +"    \"bool\": {\n" +"      \"should\": [\n" +"        { \"match\": { \"name\": \"?0\"}},\n" +"        { \"match\": { \"title\": \"?0\"}},\n" +"        { \"match\": { \"description\": \"?0\"}},\n" +"        { \"match\": { \"category_name\": \"?0\"}}\n" +"        ]\n" +"     }\n" +"}")
// 上面指定了查询语句,这个方法的方法名就随意定义了
//↓↓↓                                          ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Page<SpuForElastic> querySearch(String keyword, Pageable pageable);

修改方法的定义,原有的调用会报错,注释掉调用即可!

2.7.2开发搜索功能的业务逻辑层

提供的项目搜索功能接口的返回值泛型为虚拟机版本的ES实体类

要先修改一下

ISearchService

public interface ISearchService {// ES分页查询spu的方法//       ↓↓↓↓↓↓↓↓↓↓↓↓↓JsonPage<SpuForElastic> search(String keyword, Integer page, Integer pageSize)//......
}

SearchServiceImpl类添加实现方法如下

@Override
public JsonPage<SpuForElastic> search(String keyword, Integer page, Integer pageSize) {// 根据参数中分页的数据,执行分页,注意SpringData分页参数设置0是第一页,所以要减1Page<SpuForElastic> spus=spuRepository.querySearch(keyword,PageRequest.of(page-1,pageSize));// 当前方法需要返回JsonPage类型,我们需要将spus对象进行转换// 我们使用就地转换的方式,也可以在JsonPage类中添加转换方法来调用JsonPage<SpuForElastic> jsonPage=new JsonPage<>();// 赋值相关分页信息jsonPage.setPage(page);jsonPage.setPageSize(pageSize);//总条数和总页数jsonPage.setTotal(spus.getTotalElements());jsonPage.setTotalPage(spus.getTotalPages());// 将查询到的数据赋值到jsonPagejsonPage.setList(spus.getContent());// 最后别忘了返回return jsonPage;
}

2.7.3开发控制层代码

创建controller包

包中创建SearchController编写搜索方法,代码如下

@RestController
@RequestMapping("/search")
@Api(tags = "搜索模块")
public class SearchController {@Autowiredprivate ISearchService searchService;// 搜索模块的功能非常直接,就是搜索// 所以它的url路径可以尽量短// @GetMapping后面不写任何内容,意思就是只适用类上定义的路径即可访问// 访问路径:localhost:10008/search@GetMapping@ApiOperation("根据用户输入的关键字分页查询spu")@ApiImplicitParams({@ApiImplicitParam(value = "搜索关键字",name="keyword", dataType="string"),@ApiImplicitParam(value = "页码",name="page", dataType="int"),@ApiImplicitParam(value = "每页条数",name="pageSize", dataType="int")})public JsonResult<JsonPage<SpuForElastic>> searchByKeyword(String keyword,Integer page, Integer pageSize){JsonPage<SpuForElastic> jsonPage=searchService.search(keyword,page,pageSize);return JsonResult.ok(jsonPage);}}

保证Nacos\seata\ES启动

因为当前search项目过滤器解析JWT所以需要登录才能访问

启动search模块

建议启动passport模块去进行登录获得jwt

复制JWT后,粘贴到10008模块的全局参数,启动search模块

再测试http://localhost:10008/doc.html

3.Quartz

3.1什么是Quartz

quartz:石英钟的意思

是一个当今市面上流行的高效的任务调度管理工具

所谓"调度"就是制定好的什么时间做什么事情的计划

由OpenSymphony开源组织开发

Symphony:交响乐

是java编写的,我们使用时需要导入依赖即可

3.2为什么需要Quartz

所谓"调度"就是制定好的什么时间做什么事情的计划

我们使用过的最简单的调度方法就是Timer

但是Timer的调度功能过于单一,只能是指定时间的延时调用和周期运行

而Quartz可以更详细的指定时间,进行计划调用

3.3Quartz核心组件

调度器:Scheduler

任务:job

触发器:Trigger

调度器来配置\计划什么时间触发什么任务

简单来说就是调度器规定什么时间做什么事情

  • job(工作\任务):Quartz 实现过程中是一个接口,接口中有一个方法execute(执行的意思)

​ 我们创建一个类,实现这个接口,在方法中编写要进行的操作(执行具体任务)

​ 我们还需要一个JobDetail的类型的对象,Quartz每次执行job时

​ 会实例化job类型对象,去调用这个方法,JobDetail是用来描述Job实现类的静态信息,

​ 比如任务运行时在Quartz中的名称

  • Trigger(触发器):能够描述触发指定job的规则,分为简单触发和复杂触发

    简单触发可以使用SimplTrigger实现类.功能类似timer

    复杂触发可以使用CronTrigger实现类,内部利用cron表达式描述各种复杂的时间调度计划

  • Scheduler(调度器):一个可以规定哪个触发器绑定哪个job的容器

    在调度器中保存全部的Quartz 保存的任务

    SpringBoot框架下,添加Quartz依赖后,调度器由SpringBoot管理,我们不需要编写

3.4Cron表达式

表示2022年9月3日凌晨4点的cron表达式

0 0 4 3 9 ? 2022

  • * 表示任何值,如果在分的字段上编写*,表示每分钟都会触发

  • , 是个分割符如果秒字段我想20秒和40秒时触发两次就写 20,40

  • - 表示一个区间 秒字段5-10 表示 5,6,7,8,9,10

  • / 表示递增触发 秒字段 5/10表示5秒开始每隔10秒触发一次

    日字段编写1/3表示从每月1日起每隔3天触发一次

  • ? 表示不确定值, 因为我们在定日期时,一般确定日期就不确定是周几,相反确定周几时就不确定日期

  • L 表示last最后的意思,我们可以设置当月的最后一天,就会在日字段用L表示,

    周字段使用L表示最后一周,一般会和1-7的数字组合

    例如6L表示本月最后一周的周五

  • W (work)表示最近的工作日(单纯的周一到周五) 如果日字段编写15W表示

    每月15日最近的工作日触发,如果15日是周六就14日触发,如果15日是周日就16日触发

​ LW通常一起使用,表示本月的最后一个工作日

  • # 表示第几个,只能使用在周字段上 6#3表示每月的第三个周五

    如果#后面数字写大了,是一个不存在的日期,那就不运行了

    适合设计在母亲节或父亲节这样的日期运行

网络上可用的Cron表达式生成器很多

推荐一个Cron - 在线Cron表达式生成器

未来每年的母亲节(时间9点)

0 0 9 ? 5 1#3

未来每个月离15日最近的工作日(时间9点)

0 0 9 15W * ?

双11的0时触发

0 0 0 11 11 ?

每月10日最近的工作日9点发工资

0 0 9 10W * ?

3.5SpringBoot使用Quartz

SpringBoot框架下使用Quartz格式还是非常固定的

我们选用之前学习微服务的项目csmall减少对大项目的影响

首先添加依赖

我们选项csmall-stock-webapi模块pom文件

<!--  SpringBoot整合Quartz依赖  -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

先编写要执行的任务

当前项目模块中创建quartz包

包中创建一个QuartzJob的类,实现Job接口

代码如下

public class QuartzJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {// 实现一个简单的任务做演示// 例如输出当前时间System.out.println("-------------------"+ LocalDateTime.now() +"--------------------");}
}

上面编写的是Job接口的实现类,要想运行还需要将它封装为JobDetail对象保存在Spring容器中

还有要创建一个Trigger设置要运行的时机,也保存到Spring容器中

在quartz包下,再创建一个QuartzConfig类,其中编写它们的调度绑定关系

这个格式是固定的,后面再需要绑定,直接套用即可

// 要配置Quartz的调度器Scheduler
// 调度器由SpringBoot管理,所以就变成了配置Spring
@Configuration
public class QuartzConfig {// 配置的核心是向Spring容器保存一个job和保存一个Trigger// 创建一个封装Job对象的类型JobDetail// 使用@Bean注解标记的方法将这个对象保存到Spring容器@Beanpublic JobDetail showTime(){System.out.println("jobDetail保存到Spring容器");//newJob方法就是在绑定要运行的Job接口实现类,需要实现类的反射做参数return JobBuilder.newJob(QuartzJob.class)// 给当前JobDetail对象在调度环境中起名.withIdentity("dateTime")// 即使没有触发器绑定当前JobDetail对象,也不会被删除.storeDurably().build();}// 下面是触发器的声明,也会保存到Spring容器中// 它能够设置job的运行时机@Beanpublic Trigger showTimeTrigger(){System.out.println("Trigger保存到Spring容器中");// 定义Cron表达式CronScheduleBuilder cron=CronScheduleBuilder.cronSchedule("0 47 16 2 9 ?");return TriggerBuilder.newTrigger()// 绑定要运行的JobDetail对象.forJob(showTime())// 为触发器起名.withIdentity("dateTrigger")// 绑定cron表达式.withSchedule(cron).build();}}

Nacos\Seata需要启动

其他服务和软件都可以关闭

然后启动csmall-stock-webapi模块

观察控制台输出

3.6课上作业

在csmall-stock项目中写

利用Quart实现

每隔2分钟运行一次添加库存的操作,PC100号商品的库存添加10

public class QuartzAddStock implements Job {@Autowiredprivate IStockService stockService;@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {StockReduceCountDTO countDTO=new StockReduceCountDTO();countDTO.setCommodityCode("PC100");countDTO.setReduceCount(-10);stockService.reduceCommodityCount(countDTO);System.out.println("定时增加库存完成!");}
}
@Bean
public JobDetail addStock(){return JobBuilder.newJob(QuartzAddStock.class).withIdentity("addStock").storeDurably().build();
}
@Bean
public Trigger addStockTrigger(){CronScheduleBuilder cron=CronScheduleBuilder.cronSchedule("0 0/2 * * * ?");return TriggerBuilder.newTrigger().forJob(addStock()).withIdentity("addStockTrigger").withSchedule(cron).build();
}

4.Redis 强化

4.1缓存使用原则

什么时候,什么样的数据能够保存在Redis中?

1.数据量不能太大

2.使用越频繁,Redis保存这个数据越值得

3.保存在Redis中的数据一般不会是数据库中频繁修改的

4.2缓存淘汰策略

Redis将数据保存在内存中, 内存的容量是有限的

如果Redis服务器的内存已经全满,现在还需要向Redis中保存新的数据,如何操作,就是缓存淘汰策略

  • noeviction:返回错误**(默认)**

如果我们不想让它发生错误,就可以设置它将满足某些条件的信息删除后,再将新的信息保存

  • allkeys-random:所有数据中随机删除数据
  • volatile-random:有过期时间的数据中随机删除数据
  • volatile-ttl:删除剩余有效时间最少的数据
  • allkeys-lru:所有数据中删除上次使用时间距离现在最久的数据
  • volatile-lru:有过期时间的数据中删除上次使用时间距离现在最久的数据
  • allkeys-lfu:所有数据中删除使用频率最少的
  • volatile-lfu:有过期时间的数据中删除使用频率最少的

JSD-2204-(业务逻辑开发)-更新订单状态的功能-搜索功能-Quartz-Day12相关推荐

  1. 电商网站之更新订单状态

    电商上面订单状态的修改是非常普通的业务 随着商品的购买流程,订单的状态有: 0 = 未支付 1 = 已关闭 (超时未支付) 2 = 已取消 3 = 已支付 4 = 已签收 5 = 已拒收 6 = 退款 ...

  2. 业务逻辑开发套路的三板斧

    转自:代码这件大事 背景: 作为一个研发,我们工作中都会处理面临下面这些困惑: 又加需求,一个方法本来就处理了 300 行,现在又加 50 行. 状态逻辑太多了,产品第 2 期又加了一个逻辑,代码结构 ...

  3. java 更新订单状态_Java 8状态更新

    java 更新订单状态 即将到来的Java SE 8发行版的两大新语言功能是Lambda Expressions和Modularity. 这两天的状态更新都已经发布. 我会与您分享链接,因此您可能会在 ...

  4. 基于微信云开发的微信小程序之搜索功能的实现

    文章目录 搜索功能的设计 代码逻辑 页面设计 效果展示 搜索功能的设计 功能描述: 该模块主要是基于云开发实现小程序搜的搜索功能.如果搜索框输入为空或直接点击搜索按钮,显示对应弹窗:如果搜索框输入内容 ...

  5. JSD-2204-(业务逻辑开发)-新增订单-查询订单-Day11

    1.续 开发新增订单功能 1.1开发新增订单的业务逻辑层 我们完成订单的新增业务是比较复杂的 可以将整个业务分成三大部分 第一部分是信息的收集 主要是参数类型数据的完整性验证,计算以及转换 第二部分是 ...

  6. uniapp开发APP实现导航栏顶部搜索功能

    效果图如下: 在page.json中配置searchInput {"path": "pages/index/index","style": ...

  7. 【Lilishop商城】No4-1.业务逻辑的代码开发,涉及到:会员B端第三方登录使用及后端接口(微信、QQ等)

    仅涉及后端,全部目录看顶部专栏,代码.文档.接口路径在: [Lilishop商城]记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客 全篇会结合业务介绍重点设计逻辑,其中重点包括接口 ...

  8. 【C 语言】文件操作 ( 配置文件读写 | 业务逻辑 | 接口设计 )

    文章目录 一.配置文件读写 业务逻辑 二.接口设计 1.写文件接口 2.读文件接口 3.修改文件接口 4.接口合并 一.配置文件读写 业务逻辑 开发一个系统 , 在命令行中实现如下功能 , 通过命令操 ...

  9. java编程根据订单编号查询订单状态_Java微信订单查询

    Java 通过统一下单 API 进行订单支付后,除等待微信通过 notify_url 进行回调通知外,还可以主动查询订单状态 更多精彩 前置条件 可参考 Java 微信扫码支付 如果实现微信支付 官网 ...

最新文章

  1. 数字预失真技术基本原理
  2. mysql实时物化到clickhouse(MaterializeMySQL)
  3. [渝粤教育] 西南科技大学 工程建设监理 在线考试复习资料
  4. 随笔小杂记(二)——分割数据集和标签作为训练集和验证集
  5. php和dart交互,Flutter 之和原生交互
  6. linux软件装错了,Linux安装软件时的错误解决
  7. 动漫版宫心计:快看漫画VS动漫之家
  8. vs窗体应用程序c语言,使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)...
  9. pcsx2 linux双显卡,PC模拟PS2游戏模拟器PCSX2使用教程
  10. matlab里删除文件恢复,删除的文件如何恢复?360安全卫士找回误删文件
  11. mysql float数据类型和decimal数据类型
  12. Packet Tracer 思科模拟器入门教程 之十一 路由器静态路由配置
  13. Velodyne 64线激光雷达协议
  14. XSSFWorkbook 设置单元格样式_CVA高校精英计划第二弹:执行最佳操作,做好设置准备...
  15. 2021年金属非金属矿山支柱考试题库及金属非金属矿山支柱找解析
  16. GDUT——1169: Krito的讨伐(优先队列BFS)
  17. 校内互测题 by LMY (FSN)
  18. python-日历模块
  19. 基于java爱宠医院管理系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
  20. 详解Tomcat配置及使用

热门文章

  1. python用turtle画出给定图片的图像
  2. Vue3重点-个人项
  3. WEBGIS开发2-地图鼠标点击事件与地图标记
  4. 为什么mybatis执行sql后,映射的结果变少了
  5. C语言打印输出字符串的几种方法
  6. QMT中print内容同时输出到控制台和日志文件
  7. VS2022创建一个空网站
  8. 联想小新潮7000黑苹果教程_联想小新潮7000装win10系统教程
  9. 苹果6怎么恢复出厂设置一直不动
  10. 骁龙820A:究竟有什么与众不同?