Java Web 开发:项目二个人开发指导

2571 字
13 分钟
Java Web 开发:项目二个人开发指导

项目2个人接口开发指导#

该文档用来指导大家开发个人接口

依赖#

整合web、整合mybatis、整合pagehelper、整合shiro

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
</dependencies>

通用部分#

跨域#

跨域问题,需要在响应报文中增加一些响应头,这个是通用的部分,这时候我们使用CorsFilter来完成

@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4 对接口配置跨域设置
return new CorsFilter(source);
}
}

整合MyBatis#

引入mybatis-spring-boot-starter依赖,然后配置spring-datasource的相关配置

spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mall40?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
type: druid的全限定类名
mybatis:
type-handlers-package: typehandler的包目录

然后在启动类上增加Mapper的包目录配置

@MapperScan("com.cskaoyan.mapper")
@SpringBootApplication
public class MarketApplication {
public static void main(String[] args) {
SpringApplication.run(MarketApplication.class, args);
}
}

个人信息#

需要整合Shiro之后,通过Shiro能够拿到信息

Subject subject = SecurityUtils.getSubject();
if (subject.isAuthenticated()) {
Object primaryPrincipal = subject.getPrincipals().getPrimaryPrincipal();
//Object principal = subject.getPrincipal();
}

json格式转换#

可以使用SpringBoot的配置文件配置其格式信息

spring:
jackson:
date-format: yyyy-MM-dd
time-zone: GMT+8

@JsonFormat写在成员变量上,指定该成员变量的日期格式

  1. 接收JSON字符串,@RequestBody接收为一个引用类型对象 ,引用类型对象中有Date成员变量
  2. 响应JSON字符串,@ResponseBody响应引用类型对象 ,引用类型对象中有Date成员变量

分页配置#

引入pagehelper的starter之后,引入对应的dialect即可

pagehelper:
helper-dialect: mysql

配置文件#

spring.profiles.active

# application.yml → 主配置文件
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/cskaoyan_market?useUnicode=true&characterEncoding=utf-8
profiles:
active: root,web

比如数据用户名密码不一致的情况会导致冲突

不同的开发者,写不同的配置文件

zhangsan的配置文件

application-zhangsan.yml
spring:
datasource:
username: zhangsan
password: lovexiaofang

lisi的配置文件

application-lisi.yml
spring:
datasource:
username: lisi
password: 654321

root用户的配置文件

application-root.yml
spring:
datasource:
username: root
password: 123456

spring.profiles.active里的值不还是会冲突么?

.gitignore 把application.yml给忽略掉

具体部分#

首页信息 (/wx/home/index)#

核心点:查询首页需要的信息

响应的JSON字符串可以使用Map来封装

Map<String, Object> entity = new HashMap<>();
try {
entity.put("banner", bannerTask.get());
entity.put("channel", channelTask.get());
entity.put("couponList", couponListTask.get());
entity.put("newGoodsList", newGoodsListTask.get());
entity.put("hotGoodsList", hotGoodsListTask.get());
entity.put("brandList", brandListTask.get());
entity.put("topicList", topicListTask.get());
entity.put("floorGoodsList", floorGoodsListTask.get());
}

上面的结果可以通过多线程来分别查询,提高效率 → 每个线程中分别做以上的list的查询

其中SystemConfig.getNewLimit(),SystemConfig.getHotLimit()这些值来源于market_system表中的小程序的相关配置(也可以参考后台管理中的小程序配置)

image-20230419010708592
image-20230419010708592

ExecutorService executorService = Executors.newFixedThreadPool(10);
// 之前后台管理中的广告管理
Callable<List> bannerListCallable = () -> adService.queryIndex();
// 之前后台管理中的类目管理
Callable<List> channelListCallable = () -> categoryService.queryChannel();
// 获取优惠券列表
Callable<List> couponListCallable;
// 判断是否是登录状态
if(userId == null){
//如果是未登录,就查询所有的优惠券中的前三条
couponListCallable = () -> couponService.queryList(0, 3);
} else {
//如果是已经登录,就查询当前用户还未领取的前三张优惠券
couponListCallable = () -> couponService.queryAvailableList(userId,0, 3);
}
// 查询新添加的商品Goods,之后后台管理中的商品管理,商品上架时有选项是否是新品,根据添加时间做排序,limit获取market_system表中的值
Callable<List> newGoodsListCallable = () -> goodsService.queryByNew(0, SystemConfig.getNewLimit());
// 查询热门商品Goods,之后后台管理中的商品管理,商品上架时有选项是否是热卖,根据添加时间做排序,limit获取market_system表中的值
Callable<List> hotGoodsListCallable = () -> goodsService.queryByHot(0, SystemConfig.getHotLimit());
// 之后后台管理中的制造商管理,根据添加时间做排序,limit获取market_system表中的值
Callable<List> brandListCallable = () -> brandService.query(0, SystemConfig.getBrandLimit());
// 之前后台管理中的专题管理,根据添加时间做排序,limit获取market_system表中的值
Callable<List> topicListCallable = () -> topicService.queryList(0, SystemConfig.getTopicLimit());
// 查询类目category以及类目下的商品goods,limit获取market_system表中的值
Callable<List> floorGoodsListCallable = this::getCategoryList;
FutureTask<List> bannerTask = new FutureTask<>(bannerListCallable);
FutureTask<List> channelTask = new FutureTask<>(channelListCallable);
FutureTask<List> couponListTask = new FutureTask<>(couponListCallable);
FutureTask<List> newGoodsListTask = new FutureTask<>(newGoodsListCallable);
FutureTask<List> hotGoodsListTask = new FutureTask<>(hotGoodsListCallable);
FutureTask<List> brandListTask = new FutureTask<>(brandListCallable);
FutureTask<List> topicListTask = new FutureTask<>(topicListCallable);
FutureTask<List> floorGoodsListTask = new FutureTask<>(floorGoodsListCallable);
executorService.submit(bannerTask);
executorService.submit(channelTask);
executorService.submit(couponListTask);
executorService.submit(newGoodsListTask);
executorService.submit(hotGoodsListTask);
executorService.submit(brandListTask);
executorService.submit(topicListTask);
executorService.submit(floorGoodsListTask);

最后floorGoodsList要先获取一级类目,然后获得其二级类目,然后获得其二级类目下的商品list,期间根据market_system表中的limit做限制数据量

private List<Map> getCategoryList() {
List<Map> categoryList = new ArrayList<>();
List<CskaoyanMarketCategory> catL1List = categoryService.queryL1WithoutRecommend(0, SystemConfig.getCatlogListLimit());
for (CskaoyanMarketCategory catL1 : catL1List) {
List<CskaoyanMarketCategory> catL2List = categoryService.queryByPid(catL1.getId());
List<Integer> l2List = new ArrayList<>();
for (CskaoyanMarketCategory catL2 : catL2List) {
l2List.add(catL2.getId());
}
List<CskaoyanMarketGoods> categoryGoods;
if (l2List.size() == 0) {
categoryGoods = new ArrayList<>();
} else {
categoryGoods = goodsService.queryByCategory(l2List, 0, SystemConfig.getCatlogMoreLimit());
}
Map<String, Object> catGoods = new HashMap<>();
catGoods.put("id", catL1.getId());
catGoods.put("name", catL1.getName());
catGoods.put("goodsList", categoryGoods);
categoryList.add(catGoods);
}
return categoryList;
}

商品详情信息(/wx/goods/detail)#

核心点:获取商品的详细信息

传入的值是goodsId,然后查询相关的信息

Map<String, Object> data = new HashMap<>();
// goods的信息
data.put("info", info);
// 已经收藏该商品的用户数量
data.put("userHasCollect", userHasCollect);
// 后台管理中的通用问题
data.put("issue", issueCallableTask.get());
// 商品评论
data.put("comment", commentsCallableTsk.get());
// 规格列表 goods_specification表 → 注意按照响应结果的格式来封装
data.put("specificationList", objectCallableTask.get());
// 货品信息 goods_product表
data.put("productList", productListCallableTask.get());
// 参数信息 goods_attribute表
data.put("attribute", goodsAttributeListTask.get());
// 制造商信息
data.put("brand", brandCallableTask.get());
// 是否分享
data.put("share", SystemConfig.isAutoCreateShareImage());
// 商品分享图片地址
data.put("shareImage", info.getShareUrl());

可以参考上面/wx/home/index使用多线程来完成,也可以直接写业务代码

相关商品(/wx/goods/related)#

核心点:根据当前商品查询其相关的商品

请求参数可以直接接收

@GetMapping("related")
public BaseRespVo related(Integer id) {
CskaoyanMarketGoods goods = goodsService.findById(id);
if (goods == null) {
return BaseRespVo.badArgumentValue();
}
// 推荐同类目的其他商品
int cid = goods.getCategoryId();
// 查找六个相关商品
int related = 6;
List<CskaoyanMarketGoods> goodsList = goodsService.queryByCategory(cid, 0, related);
return BaseRespVo.ok(goodsList);
}

购物车中货品的数量(/wx/cart/goodscount)#

核心点:查询购物车中的货品数量

先查询到用户id的信息,然后根据用户用户id查询该用户的购物车中的货品数量

接下来开始继续开发吧

购物车中添加记录(/wx/cart/add)#

核心点:接收JSON数据对象,添加到数据库中,要绑定用户信息,信息要来源于Shiro,

首先获得用户信息,用户信息参考通用部分/个人信息

判断商品是否存在,

需要判断购物车是否有这个商品的记录,如果已经有的话,需要合并购物车,在已有的购物车记录上添加数量

需要根据规格判断库存

购物车(/wx/cart/index)#

查看购物车首页,查询当前用户的购物车记录,计算选中的商品(checked=1)的数量和金额

首先获得用户信息,用户信息参考通用部分/个人信息

暂时不需要写登录 → 用户先写死 Integer userId = 1; → 购物车查询的就应该是 → userId为1的这个用户的购物车

购物车商品标记(/wx/cart/checked)#

修改选中商品的选中状态(checked = !checked),然后重新执行/wx/cart/index做的事情,返回结果类型一致

立即购买(/wx/cart/fastadd)#

做的事情和/wx/cart/add基本上是一样的,add请求如果购物车中已经有这个商品了,可以做合并;fastadd如果购物车中已经有该商品了,可以覆盖掉

这里的返回值是在market_cart表中该记录的id

结账信息(/wx/cart/checkout)#

生成购物车结账信息

这个接口的计算金额部分会比较繁琐,耐心点儿做

如果cartid=0则是通过购物车下单的,查询当前用户选中的商品(checked=1)的结账信息;如果cartid !=0 则是通过商品详情页立即购买生成的下单信息,然后根据fastadd添加的cart记录计算下单信息

然后

  1. 判断地址状态,addressId=0,查询该用户的默认收货地址;不为0查询当前地址

  2. 判断优惠券状态,如果为couponId=-1,则查询可用的优惠券数量;如果大于0,则使用指定的优惠券

    • 要注意判断优惠券的可用状态:优惠券是否已经删除、该用户是否有该id对应的优惠券、优惠券是否过期、结账总金额是否满足
  3. 根据该用户的购物车中选中的记录(checked=1),计算总金额,如果金额超过运费满减金额(后台配置管理),则不添加运费,如果不超过运费满减金额,则需要添加运费,如果可以使用指定优惠券,减去优惠券的金额;也就是

    • 实付金额 = 商品合计 - (商品合计 > 运费满减金额?0:运费) - 优惠券金额

提交订单(/wx/order/submit)#

购物车结账信息再重新计算一次;额外去做的事情添加order和orderGoods记录,由于项目2不做支付,订单状态可以直接定义为待付款,删除购物车中的记录(可以逻辑删除),同时减去库存,如果库存不足可以抛出异常,给出提示信息,如果使用了优惠券,要将优惠券状态标记为已使用

额外说明#

订单信息中的handleOption是可以操作的选项,handleOption中的哪些值为true,基本上就是显示哪一些按钮

比如已付款的订单的handleOption

image-20230419232558161
image-20230419232558161

aftersale: 申请售后(这个也可以不管)

cancel:取消订单

comment:去评论(该值为true且该order_goods没有评论的前提下才会显示该按钮)

confirm:确认收货

delete:删除订单

pay:去付款

rebuy:再次购买

refund:申请退款

其中refund为true,意味着申请退款按钮显示

image-20230419232641618
image-20230419232641618

其余#

有问题及时问,目前我就是大家的产品经理

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Java Web 开发:项目二个人开发指导
https://firefly-mu-weld.vercel.app/posts/24-项目二个人开发指导/
作者
Daisy
发布于
2026-06-10
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Daisy
Hello, I'm Daisy.
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签

文章目录