目录
- 一、创建项目
- 二、项目结构
- 1.目录结构
- 1.1购物车
- 1.2订单
- 2.配置文件
- 3.Maven依赖
- 4.启动项目
一、创建项目
首先创建一个SpringBoot项目,具体创建过程和 微服务(三)—— 用户模块(backend-user).一样。
二、项目结构
1.目录结构
项目结构就是Controller、Service、Dao三层结构,由于订单和购物车耦合度比较高,所以我就将购物和订单业务放在一个模块了。
1.1购物车
(1)Controller层
主要是提供给前端的增删改查接口,完整的类如下:
package com.aiun.order.controller;
/**
* 购物车控制层
* @author lenovo
*/
@Api(tags = "购物车接口")
@RestController
@RequestMapping("/cart/")
public class CartController {
@Autowired
private ICartService iCartService;
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 添加购物车功能
* @param productId 产品id
* @param count 产品个数
* @return 封装好的购物车 VO
*/
@GetMapping("add")
@ApiOperation(value = "购物车添加商品功能")
public ServerResponse<CartVO> add(HttpServletRequest request, Integer productId, Integer count) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iCartService.add(user.getId(), productId, count);
}
return hasLogin;
}
/**
* 更新购物车商品功能
* @param productId 产品 id
* @param count 产品个数
* @return 封装好的购物车 VO
*/
@PostMapping("update")
@ApiOperation(value = "更新购物车商品功能")
public ServerResponse<CartVO> update(HttpServletRequest request, Integer productId, Integer count) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iCartService.update(user.getId(), productId, count);
}
return hasLogin;
}
/**
* 删除购物车商品
* @param productIds 多个产品的id
* @return 封装好的购物车 VO
*/
@DeleteMapping("delete_product")
@ApiOperation(value = "删除购物车商品")
public ServerResponse<CartVO> deleteProduct(HttpServletRequest request, String productIds) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iCartService.deleteProduct(user.getId(), productIds);
}
return hasLogin;
}
/**
* 查询购物车商品列表
* @return 封装好的购物车 VO
*/
@PostMapping("list")
@ApiOperation(value = "查询购物车商品列表")
public ServerResponse<CartVO> list(HttpServletRequest request) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iCartService.list(user.getId());
}
return hasLogin;
}
/**
* 全选
* @return 封装好的购物车 VO
*/
@PostMapping("select_all")
@ApiOperation(value = "购物车全选")
public ServerResponse<CartVO> selectAll(HttpServletRequest request) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iCartService.selectOrUnSelect(user.getId(), null, CartConst.Cart.CHECKED);
}
return hasLogin;
}
/**
* 反选
* @return 封装好的购物车 VO
*/
@PostMapping("un_select_all")
@ApiOperation(value = "反选")
public ServerResponse<CartVO> unSelectAll(HttpServletRequest request) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iCartService.selectOrUnSelect(user.getId(), null, CartConst.Cart.UN_CHECKED);
}
return hasLogin;
}
/**
* 单独选
* @return 封装好的购物车 VO
*/
@PostMapping("select")
@ApiOperation(value = "单独选")
public ServerResponse<CartVO> select(HttpServletRequest request, Integer productId) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iCartService.selectOrUnSelect(user.getId(), productId, CartConst.Cart.CHECKED);
}
return hasLogin;
}
/**
* 单独反选
* @return 封装好的购物车 VO
*/
@PostMapping("un_select")
@ResponseBody
@ApiOperation(value = "单独反选")
public ServerResponse<CartVO> unSelect(HttpServletRequest request, Integer productId) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iCartService.selectOrUnSelect(user.getId(), productId, CartConst.Cart.UN_CHECKED);
}
return hasLogin;
}
/**
* 查询当前用户购物车里产品的数量
* @return 返回产品的数量
*/
@PostMapping("get_cart_product_count")
@ResponseBody
@ApiOperation(value = "查询当前用户购物车里产品的数量")
public ServerResponse<Integer> getCartProductCount(HttpServletRequest request) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iCartService.getCartProductCount(user.getId());
}
return hasLogin;
}
/**
* 判断用户登录是否过期
*/
private ServerResponse<User> loginHasExpired(HttpServletRequest request) {
String key = request.getHeader(UserConst.AUTHORITY);
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
String value = valueOperations.get(key);
if (StringUtils.isEmpty(value)) {
return ServerResponse.createByErrorMessage(ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());
}
User user = JsonUtils.jsonStr2Object(value, User.class);
if (!key.equals(user.getUsername())) {
return ServerResponse.createByErrorMessage(ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());
}
valueOperations.set(key, value, 1, TimeUnit.HOURS);
return ServerResponse.createBySuccess(user);
}
}
该类里面有一个私有的方法,是用于用户权限验证的
(2)Service层
该层是业务的主要实现,下面看一下Service的实现类:
package com.aiun.order.service.impl;
/**
* @author lenovo
*/
@Service("iCartService")
public class CartServiceImpl implements ICartService {
@Autowired
private CartMapper cartMapper;
@Autowired
private ProductFeign productFeign;
@Value("mageHost")
private String mageHost;
@Override
public ServerResponse<CartVO> add(Integer userId, Integer productId, Integer count) {
if (productId == null || count == null) {
return ServerResponse.createByErrorMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(), ResponseCode.ILLEGAL_ARGUMENT.getDesc());
}
Cart cart = cartMapper.selectCartByUserIdProductId(userId, productId);
if (cart == null) {
//产品不在购物车里,需要新增一个这个产品的记录
Cart cartItem = new Cart();
cartItem.setQuantity(count)
.setChecked(CartConst.Cart.CHECKED)
.setProductId(productId)
.setUserId(userId);
int resultCount = cartMapper.insert(cartItem);
if (resultCount == 0){
return ServerResponse.createByErrorMessage("添加购物车失败");
}
} else {
//这个产品已经在购物车里了
//需要将数量相加
count = cart.getQuantity() + count;
cart.setQuantity(count);
cartMapper.updateByPrimaryKeySelective(cart);
}
return this.list(userId);
}
@Override
public ServerResponse<CartVO> update(Integer userId, Integer productId, Integer count) {
if (productId == null || count == null) {
return ServerResponse.createByErrorMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(), ResponseCode.ILLEGAL_ARGUMENT.getDesc());
}
Cart cart = cartMapper.selectCartByUserIdProductId(userId, productId);
if (cart != null) {
cart.setQuantity(count);
}
int resoultCount = cartMapper.updateByPrimaryKeySelective(cart);
if (resoultCount == 0) {
return ServerResponse.createByErrorMessage("更新购物车失败");
}
return this.list(userId);
}
@Override
public ServerResponse<CartVO> deleteProduct(Integer userId, String productIds) {
List<String> productList = new ArrayList<>();
String[] productIdStrings = productIds.split(",");
for(String id : productIdStrings) {
productList.add(id);
}
if (productList.isEmpty()) {
return ServerResponse.createByErrorMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(), ResponseCode.ILLEGAL_ARGUMENT.getDesc());
}
cartMapper.deleteByUserIdProductIds(userId, productList);
return this.list(userId);
}
@Override
public ServerResponse<CartVO> list(Integer userId) {
CartVO cartVo = this.getCartVoLimit(userId);
return ServerResponse.createBySuccess(cartVo);
}
@Override
public ServerResponse<CartVO> selectOrUnSelect(Integer userId, Integer productId, Integer checked) {
cartMapper.checkedOrUnCheckedProduct(userId, productId, checked);
return this.list(userId);
}
@Override
public ServerResponse<Integer> getCartProductCount(Integer userId) {
if (userId == null) {
return ServerResponse.createBySuccess(0);
}
return ServerResponse.createBySuccess(cartMapper.selectCartProductCount(userId));
}
/**
* 封装前端用到的购物车数据
* @param userId 用户 id
* @return 封装的购物车 VO
*/
private CartVO getCartVoLimit(Integer userId) {
CartVO cartVo = new CartVO();
List<Cart> cartList = cartMapper.selectCartByUserId(userId);
List<CartProductVO> cartProductVOList = Lists.newArrayList();
BigDecimal cartTotalPrice = new BigDecimal("0");
if (!cartList.isEmpty()) {
for (Cart cartItem : cartList) {
CartProductVO cartProductVo = new CartProductVO();
cartProductVo.setId(cartItem.getId())
.setProductId(cartItem.getProductId())
.setUserId(cartItem.getUserId());
Product product = productFeign.findById(cartItem.getProductId());
if (product != null) {
cartProductVo.setProductMainImage(product.getMainImage())
.setProductName(product.getName())
.setProductPrice(product.getPrice())
.setProductStatus(product.getStatus())
.setProductSubtitle(product.getSubtitle())
.setProductStock(product.getStock());
//判断库存
int buyLimitCount = 0;
if (product.getStock() >= cartItem.getQuantity()) {
buyLimitCount = cartItem.getQuantity();
cartProductVo.setLimitQuantity(CartConst.LIMIT_NUM_SUCCESS);
} else {
buyLimitCount = product.getStock();
cartProductVo.setLimitQuantity(CartConst.LIMIT_NUM_FAIL);
//购物车中更新有效库存
Cart cartForQuantity = new Cart();
cartForQuantity.setId(cartItem.getId())
.setQuantity(buyLimitCount);
cartMapper.updateByPrimaryKeySelective(cartForQuantity);
}
cartProductVo.setQuantity(buyLimitCount);
//计算总价
cartProductVo.setProductTotalPrice(BigDecimalUtils.mul(product.getPrice().doubleValue(), cartProductVo.getQuantity()))
.setProductChecked(cartItem.getChecked());
}
if (cartItem.getChecked() == CartConst.Cart.CHECKED) {
//如果已经勾选,增加到整个购物车的总价中
cartTotalPrice = BigDecimalUtils.add(cartTotalPrice.doubleValue(), cartProductVo.getProductTotalPrice().doubleValue());
}
cartProductVOList.add(cartProductVo);
}
}
cartVo.setCartTotalPrice(cartTotalPrice)
.setCartProductVOList(cartProductVOList)
.setAllChecked(this.getAllCheckedStatus(userId))
.setImageHost(mageHost);
return cartVo;
}
/**
* 查询是否是全选中状态
* @param userId 用户 id
* @return 产品是否是选中状态
*/
private boolean getAllCheckedStatus(Integer userId) {
if (userId == null) {
return false;
}
return cartMapper.selectCartProductCheckedStatusByUserId(userId) == 0;
}
}
这个类主要是订单的创建,以及查询商品的选中状态,然后计算价格。
计算价格的时候需要注意精度丢失问题,这里选用BigDecimal类,通过字符串的方式构造对象可以防止精度丢失。
(3)Dao层
首先是Mapper接口层
package com.aiun.order.mapper;
@Mapper
@Component
public interface CartMapper {
/**
* 通过主键删除购物车
* @param id 主键
* @return 影响的记录行
*/
int deleteByPrimaryKey(Integer id);
/**
* 插入购物车信息
* @param record 购物车信息
* @return 影响的记录行
*/
int insert(@Param("record") Cart record);
/**
* 有选择的插入购物车信息
* @param record 购物车信息
* @return 影响的记录行
*/
int insertSelective(@Param("record") Cart record);
/**
* 通过主键有选择的插入
* @param id 主键
* @return 购物车信息
*/
Cart selectByPrimaryKey(Integer id);
/**
* 通过主键有选择的更新购物车数据
* @param record 购物车
* @return 影响的记录行
*/
int updateByPrimaryKeySelective(@Param("record") Cart record);
/**
* 通过主键更新购物车数据
* @param record 购物车信息
* @return 影响的记录行
*/
int updateByPrimaryKey(@Param("record") Cart record);
/**
* 根据用户Id查询商品选中状态
* @param userId 用户 id
* @return 所有购物车信息
*/
List<Cart> selectCheckedCartByUserId(Integer userId);
/**
* 通过用户id和产品id查询购物车
* @param userId 用户 id
* @param productId 产品 id
* @return 购物车信息
*/
Cart selectCartByUserIdProductId(@Param("userId") Integer userId, @Param("productId") Integer productId);
/**
* 通过用户id查询购物车
* @param userId 用户 id
* @return 购物车信息
*/
List<Cart> selectCartByUserId(Integer userId);
/**
* 根据用户id和产品id删除
* @param userId 用户 id
* @param productIds 需要删除的产品 id
* @return 影响的记录行
*/
int deleteByUserIdProductIds(@Param("userId") Integer userId, @Param("productIds") List<String> productIds);
/**
* 更新购物车产品的选中状态
* @param userId 用户 id
* @param productId 需要选中的产品 id
* @param checked 选中状态
* @return 影响的记录行
*/
int checkedOrUnCheckedProduct(@Param("userId") Integer userId, @Param("productId") Integer productId, @Param("checked") Integer checked);
/**
* 获取购物车产品数量
* @param userId 用户 id
* @return 影响的记录行
*/
int selectCartProductCount(@Param("userId") Integer userId);
/**
* 根据userId查询产品是否有未被选中的
* @param userId 用户 id
* @return 影响的记录行
*/
int selectCartProductCheckedStatusByUserId(Integer userId);
}
对应的Mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.aiun.order.mapper.CartMapper" >
<resultMap id="BaseResultMap" type="com.aiun.order.pojo.Cart" >
<constructor >
<idArg column="id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="user_id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="product_id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="quantity" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="checked" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="create_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
<arg column="update_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
</constructor>
</resultMap>
<sql id="Base_Column_List" >
id, user_id, product_id, quantity, checked, create_time, update_time
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from trade_cart
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from trade_cart
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.aiun.order.pojo.Cart" >
insert into trade_cart (id, user_id, product_id,
quantity, checked, create_time,
update_time)
values (#{record.id,jdbcType=INTEGER}, #{record.userId,jdbcType=INTEGER}, #{record.productId,jdbcType=INTEGER},
#{record.quantity,jdbcType=INTEGER}, #{record.checked,jdbcType=INTEGER}, now(),
now())
</insert>
<insert id="insertSelective" parameterType="com.aiun.order.pojo.Cart" >
insert into trade_cart
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="record.id != null" >
id,
</if>
<if test="record.userId != null" >
user_id,
</if>
<if test="record.productId != null" >
product_id,
</if>
<if test="record.quantity != null" >
quantity,
</if>
<if test="record.checked != null" >
checked,
</if>
<if test="record.createTime != null" >
create_time,
</if>
<if test="record.updateTime != null" >
update_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="record.id != null" >
#{record.id,jdbcType=INTEGER},
</if>
<if test="record.userId != null" >
#{record.userId,jdbcType=INTEGER},
</if>
<if test="record.productId != null" >
#{record.productId,jdbcType=INTEGER},
</if>
<if test="record.quantity != null" >
#{record.quantity,jdbcType=INTEGER},
</if>
<if test="record.checked != null" >
#{record.checked,jdbcType=INTEGER},
</if>
<if test="record.createTime != null" >
now(),
</if>
<if test="record.updateTime != null" >
now(),
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.aiun.order.pojo.Cart" >
update trade_cart
<set >
<if test="record.userId != null" >
user_id = #{record.userId,jdbcType=INTEGER},
</if>
<if test="record.productId != null" >
product_id = #{record.productId,jdbcType=INTEGER},
</if>
<if test="record.quantity != null" >
quantity = #{record.quantity,jdbcType=INTEGER},
</if>
<if test="record.checked != null" >
checked = #{record.checked,jdbcType=INTEGER},
</if>
<if test="record.createTime != null" >
create_time = #{record.createTime,jdbcType=TIMESTAMP},
</if>
<if test="record.updateTime != null" >
update_time = now(),
</if>
</set>
where id = #{record.id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.aiun.order.pojo.Cart" >
update trade_cart
set user_id = #{record.userId,jdbcType=INTEGER},
product_id = #{record.productId,jdbcType=INTEGER},
quantity = #{record.quantity,jdbcType=INTEGER},
checked = #{record.checked,jdbcType=INTEGER},
create_time = #{record.createTime,jdbcType=TIMESTAMP},
update_time = now()
where id = #{record.id,jdbcType=INTEGER}
</update>
<select id="selectCartByUserIdProductId" resultMap="BaseResultMap" parameterType="map">
select
<include refid="Base_Column_List"/>
from trade_cart
where user_id = #{userId}
and product_id = #{productId}
</select>
<select id="selectCartByUserId" resultMap="BaseResultMap" parameterType="int">
select
<include refid="Base_Column_List"/>
from trade_cart
where user_id = #{userId}
</select>
<select id="selectCartProductCheckedStatusByUserId" resultType="int" parameterType="int">
select count(1) from trade_cart where checked = 0 and user_id = #{userId}
</select>
<delete id="deleteByUserIdProductIds" parameterType="map">
delete from trade_cart
where user_id = #{userId}
<if test="productIds != null">
and product_id in
<foreach collection="productIds" item="item" index="index" open="(" separator="," close=")">
#{item}
</foreach>
</if>
</delete>
<update id="checkedOrUnCheckedProduct" parameterType="map">
update trade_cart
set checked = #{checked},
update_time = now()
where user_id = #{userId}
<if test="productId != null">
and product_id = #{productId}
</if>
</update>
<select id="selectCartProductCount" resultType="int" parameterType="int">
select IFNULL(sum(quantity), 0) as count from trade_cart where user_id = #{userId}
</select>
<select id="selectCheckedCartByUserId" resultMap="BaseResultMap" parameterType="int">
SELECT
<include refid="Base_Column_List"/>
FROM trade_cart
WHERE user_id = #{userId}
AND checked = 1
</select>
</mapper>
配置文件和Maven依赖看后面介绍。
1.2订单
(1)Controller层
OrderController类如下:
package com.aiun.order.controller;
/**
* 订单控制层
* @author lenovo
*/
@Api(tags = "订单系统相关接口")
@RestController
@FeignClient
@RequestMapping("/order/")
public class OrderController {
@Autowired
private IOrderService iOrderService;
@Autowired
private RedisTemplate<String,String> redisTemplate;
/**
* 创建订单
* @param request 请求
* @param shippingId 收货地址id
* @return 结果
*/
@GetMapping("create")
@ApiOperation(value = "创建订单")
public ServerResponse create(HttpServletRequest request, Integer shippingId) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iOrderService.createOrder(user.getId(), shippingId);
}
return hasLogin;
}
/**
* 取消订单
* @param request 请求
* @param orderNo 订单号
* @return 返回结果
*/
@PostMapping("cancel")
@ApiOperation(value = "取消订单")
public ServerResponse cancel(HttpServletRequest request, Long orderNo) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iOrderService.cancel(user.getId(), orderNo);
}
return hasLogin;
}
/**
* 获取购物车中已经选中的商品信息
* @param request 请求
* @return 返回结果
*/
@PostMapping("get_order_cart_product")
@ApiOperation(value = "获取购物车中已经选中的商品信息")
public ServerResponse getOrderCartProduct(HttpServletRequest request) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
return iOrderService.getOrderCartProduct(user.getId());
}
return hasLogin;
}
/**
* 获取订单详细信息
* @param request 请求
* @param orderNo 订单号
* @return 订单详情
*/
@PostMapping("detail")
@ApiOperation(value = "获取订单详细信息")
public ServerResponse detail(HttpServletRequest request, Long orderNo) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
if (user.getRole() == UserConst.Role.ROLE_ADMIN) {
return iOrderService.getOrderDetail(null, orderNo);
} else {
return iOrderService.getOrderDetail(user.getId(), orderNo);
}
}
return hasLogin;
}
/**
* 获取订单列表信息
* @param request 请求
* @param pageNum 分页的当前页
* @param pageSize 页的大小
* @return 返回订单列表信息
*/
@PostMapping("list")
@ApiOperation(value = "获取订单列表信息")
public ServerResponse list(HttpServletRequest request, @RequestParam(value = "pageNum", defaultValue = "1") int pageNum, @RequestParam(value = "pageSize", defaultValue = "10") int pageSize) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
if (user.getRole() == UserConst.Role.ROLE_ADMIN) {
return iOrderService.getOrderList(null, pageNum, pageSize);
} else {
return iOrderService.getOrderList(user.getId(), pageNum, pageSize);
}
}
return hasLogin;
}
/**
* 订单查询
* @param request 请求
* @param orderNo 订单号
* @param pageNum 当前页
* @param pageSize 页大小
* @return 返回结果
*/
@PostMapping("manage/search")
@ApiOperation(value = "订单查询")
public ServerResponse<PageInfo> orderSearch(HttpServletRequest request, Long orderNo, @RequestParam(value = "pageNum", defaultValue = "1") int pageNum, @RequestParam(value = "pageSize", defaultValue = "10") int pageSize) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
if (user.getRole() == UserConst.Role.ROLE_ADMIN) {
return iOrderService.manageSearch(orderNo, pageNum, pageSize);
} else {
return ServerResponse.createByErrorMessage("无权限操作,需要管理员权限");
}
}
return hasLogin;
}
/**
* 发货
* @param request 请求
* @param orderNo 订单号
* @return 发货信息
*/
@PostMapping("send_goods")
@ApiOperation(value = "发货")
public ServerResponse<String> orderSendGoods(HttpServletRequest request, Long orderNo) {
ServerResponse hasLogin = loginHasExpired(request);
if (hasLogin.isSuccess()) {
User user = (User) hasLogin.getData();
if (user.getRole() == UserConst.Role.ROLE_ADMIN) {
return iOrderService.manageSendGoods(orderNo);
} else {
return ServerResponse.createByErrorMessage("无权限操作,需要管理员权限");
}
}
return hasLogin;
}
/**
* 判断用户登录是否过期
*/
private ServerResponse<User> loginHasExpired(HttpServletRequest request) {
String key = request.getHeader(UserConst.AUTHORITY);
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
String value = valueOperations.get(key);
if (StringUtils.isEmpty(value)) {
return ServerResponse.createByErrorMessage(ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());
}
User user = JsonUtils.jsonStr2Object(value, User.class);
if (!key.equals(user.getUsername())) {
return ServerResponse.createByErrorMessage(ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());
}
valueOperations.set(key, value, 1, TimeUnit.HOURS);
return ServerResponse.createBySuccess(user);
}
}
Controller层没什么业务逻辑,比较简单。
(2)Service层
看一下Service层的实现类:
package com.aiun.order.service.impl;
/**
* 订单服务层实现类
* @author lenovo
*/
@Service("iOrderService")
public class OrderServiceImpl implements IOrderService {
@Value("${image.localhost}")
private String mageHost;
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderItemMapper orderItemMapper;
@Autowired
private CartMapper cartMapper;
@Autowired
private ProductFeign productFeign;
@Autowired
private ShippingFeign shippingFeign;
@Override
public ServerResponse<OrderVO> createOrder(Integer userId, Integer shippingId) {
//从购物车中获取数据
List<Cart> cartList = cartMapper.selectCheckedCartByUserId(userId);
//计算订单的总价
ServerResponse serverResponse = getCartOrderItem(userId, cartList);
if (!serverResponse.isSuccess()) {
return serverResponse;
}
List<OrderItem> orderItemList = (List<OrderItem>) serverResponse.getData();
if (CollectionUtils.isEmpty(orderItemList)) {
return ServerResponse.createByErrorMessage("购物车为空");
}
//计算订单总价
BigDecimal payment = getOrderTotalPrice(orderItemList);
//生成订单
Order order = assembleOrder(userId, shippingId, payment);
if (order == null) {
return ServerResponse.createByErrorMessage("生成订单错误");
}
orderItemList.forEach(e->e.setOrderNo(order.getOrderNo()));
//mybatis批量插入
orderItemMapper.batchInsert(orderItemList);
//生成成功,减少产品的库存
reduceProductStock(orderItemList);
//清空购物车
cleanCart(cartList);
//返回数据给前端
OrderVO orderVo = assembleOrderVo(order, orderItemList);
return ServerResponse.createBySuccess(orderVo);
}
@Override
public ServerResponse<String> cancel(Integer userId, Long orderNo) {
Order order = orderMapper.selectByUserIdAndOrderNo(userId, orderNo);
if (order == null) {
return ServerResponse.createByErrorMessage("该用户没有此订单");
}
if (order.getStatus() != OrderStatusEnum.NO_PAY.getCode()) {
return ServerResponse.createByErrorMessage("订单已付款,无法取消!");
}
Order updateOrder = new Order();
updateOrder.setId(order.getId())
.setStatus(OrderStatusEnum.CANCELED.getCode());
int rowCount = orderMapper.updateByPrimaryKeySelective(updateOrder);
if (rowCount > 0) {
return ServerResponse.createBySuccess();
}
return ServerResponse.createByError();
}
@Override
public ServerResponse getOrderCartProduct(Integer userId) {
OrderProductVO orderProductVo = new OrderProductVO();
//从购物车中获取数据
List<Cart> cartList = cartMapper.selectCheckedCartByUserId(userId);
ServerResponse serverResponse = getCartOrderItem(userId, cartList);
if (!serverResponse.isSuccess()) {
return serverResponse;
}
List<OrderItem> orderItemList = (List<OrderItem>) serverResponse.getData();
List<OrderItemVO> orderItemVOList = Lists.newArrayList();
BigDecimal payment = new BigDecimal("0");
for (OrderItem orderItem : orderItemList) {
payment = BigDecimalUtils.add(payment.doubleValue(), orderItem.getTotalPrice().doubleValue());
orderItemVOList.add(assembleOrderItemVo(orderItem));
}
orderProductVo.setProductTotalPrice(payment)
.setOrderItemVOList(orderItemVOList)
.setImageHost(mageHost);
return ServerResponse.createBySuccess(orderProductVo);
}
@Override
public ServerResponse<OrderVO> getOrderDetail(Integer userId, Long orderNo) {
Order order;
// userId == null 表示管理员
if (userId == null) {
order = orderMapper.selectByOrderNo(orderNo);
} else {
order = orderMapper.selectByUserIdAndOrderNo(userId, orderNo);
}
List<OrderItem> orderItemList;
if (order != null) {
orderItemList = (userId == null ? orderItemMapper.getByOrderNo(orderNo) : orderItemMapper.getByOrderNoAndUserId(orderNo, userId));
OrderVO orderVo = assembleOrderVo(order, orderItemList);
return ServerResponse.createBySuccess(orderVo);
}
return ServerResponse.createByErrorMessage("没有找到该订单");
}
@Override
public ServerResponse<PageInfo> getOrderList(Integer userId, int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<OrderVO> orderVOList;
List<Order> orderList;
// 管理员
if (userId == null) {
orderList = orderMapper.selectAllOrder();
orderVOList = assembleOrderVoList(orderList, userId);
} else { // 普通用户
orderList = orderMapper.selectByUserId(userId);
orderVOList = assembleOrderVoList(orderList, userId);
}
PageInfo pageInfo = new PageInfo(orderList);
pageInfo.setList(orderVOList);
return ServerResponse.createBySuccess(pageInfo);
}
@Override
public ServerResponse<String> manageSendGoods(Long orderNo) {
Order order = orderMapper.selectByOrderNo(orderNo);
if (order != null) {
if (order.getStatus() == OrderStatusEnum.PAID.getCode()) {
order.setStatus(OrderStatusEnum.SHIPPED.getCode())
.setSendTime(new Date());
orderMapper.updateByPrimaryKeySelective(order);
return ServerResponse.createBySuccessMessage("发货成功");
}
}
return ServerResponse.createByErrorMessage("订单不存在");
}
@Override
public ServerResponse<PageInfo> manageSearch(Long orderNo, int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
Order order = orderMapper.selectByOrderNo(orderNo);
if (order != null) {
List<OrderItem> orderItemList = orderItemMapper.getByOrderNo(orderNo);
OrderVO orderVo = assembleOrderVo(order, orderItemList);
PageInfo pageInfo = new PageInfo(Lists.newArrayList(order));
pageInfo.setList(Lists.newArrayList(orderVo));
return ServerResponse.createBySuccess(pageInfo);
}
return ServerResponse.createByErrorMessage("订单不存在");
}
/**
* 购物车内数据的封装
* @param userId 用户id
* @param cartList 该用户的购物车列表
* @return 操作结果
*/
private ServerResponse getCartOrderItem(Integer userId, List<Cart> cartList) {
List<OrderItem> orderItemList = Lists.newArrayList();
if (CollectionUtils.isEmpty(cartList)) {
ServerResponse.createByErrorMessage("购物车为空");
}
//校验购物车的数据,包括产品的状态和数量
for(Cart cartItem : cartList) {
OrderItem orderItem = new OrderItem();
Product product = productFeign.findById(cartItem.getProductId());
if (ProductStatusEnum.ON_SALE.getCode() != product.getStatus()) {
return ServerResponse.createByErrorMessage("产品" + product.getName() + "不是在线售卖状态");
}
//校验库存
if (cartItem.getQuantity() > product.getStock()) {
return ServerResponse.createByErrorMessage("产品" + product.getName() + "库存数量不足");
}
orderItem.setUserId(userId)
.setProductId(product.getId())
.setProductImage(product.getMainImage())
.setProductName(product.getName())
.setCurrentUnitPrice(product.getPrice())
.setQuantity(cartItem.getQuantity())
.setTotalPrice(BigDecimalUtils.mul(product.getPrice().doubleValue(), cartItem.getQuantity().doubleValue()));
orderItemList.add(orderItem);
}
//TODO 用 Lambda 表达式
return ServerResponse.createBySuccess(orderItemList);
}
/**
* 计算购物车内购买商品总价
* @param orderItemList 用户所有购买的商品
* @return 支付金额
*/
private BigDecimal getOrderTotalPrice(List<OrderItem> orderItemList) {
BigDecimal payment = new BigDecimal("0");
for(OrderItem orderItem : orderItemList) {
payment = BigDecimalUtils.add(payment.doubleValue(), orderItem.getTotalPrice().doubleValue());
}
return payment;
}
/**
* 生成订单
* @param userId 用户id
* @param shippingId 地址id
* @param payment 支付金额
* @return 订单
*/
private Order assembleOrder(Integer userId, Integer shippingId, BigDecimal payment) {
Order order = new Order();
long orderNo = generateOrderNo();
order.setOrderNo(orderNo)
.setStatus(OrderStatusEnum.NO_PAY.getCode())
.setPostage(0)
.setPaymentType(PaymentTypeEnum.ONLINE_PAY.getCode())
.setPayment(payment)
.setUserId(userId)
.setShippingId(shippingId);
//发货时间,付款时间,后面会填充
int rowCount = orderMapper.insert(order);
if (rowCount > 0) {
return order;
}
return null;
}
/**
* 生成订单号
* @return 订单号
*/
private long generateOrderNo() {
long currentTime = System.currentTimeMillis();
//并发量高的会造成订单重复
return currentTime + new Random().nextInt(100);
}
/**
* 减少商品库存
* @param orderItemList 订单详情列表
*/
private void reduceProductStock(List<OrderItem> orderItemList) {
orderItemList.forEach(e->{
Product product = productFeign.findById(e.getProductId());
productFeign.updateStockById(e.getProductId(), product.getStock() - e.getQuantity());
});
}
/**
* 清空购物车
* @param cartList 购物车列表
*/
private void cleanCart(List<Cart> cartList) {
cartList.forEach(e->{
cartMapper.deleteByPrimaryKey(e.getId());
});
}
/**
* 封装订单数据
* @param order 订单
* @param orderItemList 订单详情列表
* @return 封装的订单对象
*/
private OrderVO assembleOrderVo(Order order, List<OrderItem> orderItemList) {
OrderVO orderVo = new OrderVO();
orderVo.setOrderNo(order.getOrderNo())
.setPayment(order.getPayment())
.setPaymentType(order.getPaymentType())
.setPaymentTypeDesc(PaymentTypeEnum.codeOf(order.getPaymentType()).getValue())
.setPostage(order.getPostage())
.setStatus(order.getStatus())
.setStatusDesc(OrderStatusEnum.codeOf(order.getStatus()).getValue())
.setShippingId(order.getShippingId());
Shipping shipping = shippingFeign.findById(order.getShippingId());
if (shipping != null) {
orderVo.setReceiverName(shipping.getReceiverName())
.setShippingVo(assembleShippingVo(shipping));
}
orderVo.setPaymentTime(DateUtils.dateToString(order.getPaymentTime()))
.setSendTime(DateUtils.dateToString(order.getSendTime()))
.setCreateTime(DateUtils.dateToString(order.getCreateTime()))
.setCloseTime(DateUtils.dateToString(order.getCloseTime()))
.setEndTime(DateUtils.dateToString(order.getEndTime()))
.setImageHost(mageHost);
List<OrderItemVO> orderItemVOList = Lists.newArrayList();
orderItemList.forEach(e->{
OrderItemVO orderItemVo = assembleOrderItemVo(e);
orderItemVOList.add(orderItemVo);
});
orderVo.setOrderItemVOList(orderItemVOList);
return orderVo;
}
/**
* 给前端返回的地址数据
* @param shipping 地址实体类
* @return 地址信息封装 VO
*/
private ShippingVo assembleShippingVo(Shipping shipping) {
ShippingVo shippingVo = new ShippingVo();
shippingVo.setReceiverAddress(shipping.getReceiverAddress())
.setReceiverCity(shipping.getReceiverCity())
.setReceiverDistrict(shipping.getReceiverDistrict())
.setReceiverMobile(shipping.getReceiverMobile())
.setReceiverName(shipping.getReceiverName())
.setReceiverProvince(shipping.getReceiverProvince())
.setReceiverPhone(shipping.getReceiverPhone())
.setReceiverZip(shipping.getReceiverZip());
return shippingVo;
}
/**
* 封装订单详情前端数据
* @param orderItem 订单详情
* @return 订单详情信息封装 VO
*/
private OrderItemVO assembleOrderItemVo(OrderItem orderItem) {
OrderItemVO orderItemVo = new OrderItemVO();
orderItemVo.setOrderNo(orderItem.getOrderNo())
.setProductId(orderItem.getProductId())
.setProductName(orderItem.getProductName())
.setProductImage(orderItem.getProductImage())
.setTotalPrice(orderItem.getTotalPrice())
.setCurrentUnitPrice(orderItem.getCurrentUnitPrice())
.setQuantity(orderItem.getQuantity())
.setCreateTime(DateUtils.dateToString(orderItem.getCreateTime()));
return orderItemVo;
}
/**
* 封装订单 vo 信息
* @param orderList 订单列表
* @param userId 用户 id
* @return 订单展示列表
*/
private List<OrderVO> assembleOrderVoList(List<Order> orderList, Integer userId) {
List<OrderVO> orderVOList = Lists.newArrayList();
for (Order order : orderList) {
List<OrderItem> orderItemList = Lists.newArrayList();
if (userId == null) {
//管理员不需要userId
orderItemList = orderItemMapper.getByOrderNo(order.getOrderNo());
} else {
orderItemList = orderItemMapper.getByOrderNoAndUserId(order.getOrderNo(), userId);
}
OrderVO orderVo = assembleOrderVo(order, orderItemList);
orderVOList.add(orderVo);
}
return orderVOList;
}
}
(3)Dao层
Mapper层有两个接口OrderMapper和OrderItemMapper
package com.aiun.order.mapper;
/**
* order模块映射接口
* @author lenovo
*/
@Mapper
@Component
public interface OrderMapper {
/**
* 通过主键删除订单
* @param id 主键
* @return 影响行数
*/
int deleteByPrimaryKey(Integer id);
/**
* 创建订单
* @param record 订单信息
* @return 影响行数
*/
int insert(@Param("record") Order record);
/**
* 有选择的创建订单
* @param record 订单信息
* @return 影响行数
*/
int insertSelective(@Param("record") Order record);
/**
* 有选择的通过主键创建订单
* @param id 主键
* @return 订单
*/
Order selectByPrimaryKey(Integer id);
/**
* 有选择的通过主键更新订单
* @param record 订单信息
* @return 影响行数
*/
int updateByPrimaryKeySelective(@Param("record") Order record);
/**
* 修改订单
* @param record 订单信息
* @return 影响行数
*/
int updateByPrimaryKey(@Param("record") Order record);
/**
* 通过用户id和订单和查询订单
* @param userId 用户id
* @param orderNo 订单号
* @return 订单
*/
Order selectByUserIdAndOrderNo(@Param("userId") Integer userId, @Param("orderNo") Long orderNo);
/**
* 通过订单号查询订单
* @param orderNo 订单号
* @return 订单
*/
Order selectByOrderNo(Long orderNo);
/**
* 通过用户 id 查询订单
* @param userId 用户 id
* @return 返回用户所有的订单
*/
List<Order> selectByUserId(Integer userId);
/**
* 查询所有的订单
* @return 返回订单列表
*/
List<Order> selectAllOrder();
}
package com.aiun.order.mapper;
/**
* 订单详情映射接口
* @author lenovo
*/
@Mapper
@Component
public interface OrderItemMapper {
/**
* 通过主键删除订单详情
* @param id 主键
* @return 影响行数
*/
int deleteByPrimaryKey(Integer id);
/**
* 插入订单详情信息
* @param record 订单详情信息
* @return 影响行数
*/
int insert(@Param("record") OrderItem record);
/**
*
* @param record 订单详情信息
* @return 影响行数
*/
int insertSelective(@Param("record") OrderItem record);
/**
* 通过主键查询订单详情
* @param id 主键
* @return 订单详情信息
*/
OrderItem selectByPrimaryKey(Integer id);
/**
* 通过主键有选择的更新订单详情信息
* @param record 订单详情信息
* @return 影响行数
*/
int updateByPrimaryKeySelective(@Param("record") OrderItem record);
/**
* 通过主键更新订单详情
* @param record 订单详情信息
* @return 影响行数
*/
int updateByPrimaryKey(@Param("record") OrderItem record);
/**
* 通过订单号获取订单详情
* @param orderNo 订单号
* @return 订单详情信息列表
*/
List<OrderItem> getByOrderNo(@Param("orderNo") Long orderNo);
/**
* 通过订单号和用户 id 获取订单详情
* @param orderNo 订单号
* @param userId 用户 id
* @return 订单详情信息列表
*/
List<OrderItem> getByOrderNoAndUserId(@Param("orderNo") Long orderNo, @Param("userId") Integer userId);
/**
* 订单详情批量插入
* @param orderItemList 订单信息列表
*/
void batchInsert(@Param("orderItemList") List<OrderItem> orderItemList);
}
订单我创建了订单表和订单详情表,所以需要两个Mapper,每个Mapper操作一个表。
下面看一下OrderMapper.xml和OrderItemMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.aiun.order.mapper.OrderMapper" >
<resultMap id="BaseResultMap" type="com.aiun.order.pojo.Order" >
<constructor >
<idArg column="id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="order_no" jdbcType="BIGINT" javaType="java.lang.Long" />
<arg column="user_id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="shipping_id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="payment" jdbcType="DECIMAL" javaType="java.math.BigDecimal" />
<arg column="payment_type" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="postage" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="status" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="payment_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
<arg column="send_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
<arg column="end_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
<arg column="close_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
<arg column="create_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
<arg column="update_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
</constructor>
</resultMap>
<sql id="Base_Column_List" >
id, order_no, user_id, shipping_id, payment, payment_type, postage, status, payment_time,
send_time, end_time, close_time, create_time, update_time
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from trade_order
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from trade_order
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.aiun.order.pojo.Order" >
insert into trade_order (id, order_no, user_id,
shipping_id, payment, payment_type,
postage, status, payment_time,
send_time, end_time, close_time,
create_time, update_time)
values (#{record.id,jdbcType=INTEGER}, #{record.orderNo,jdbcType=BIGINT}, #{record.userId,jdbcType=INTEGER},
#{record.shippingId,jdbcType=INTEGER}, #{record.payment,jdbcType=DECIMAL}, #{record.paymentType,jdbcType=INTEGER},
#{record.postage,jdbcType=INTEGER}, #{record.status,jdbcType=INTEGER}, #{record.paymentTime,jdbcType=TIMESTAMP},
#{record.sendTime,jdbcType=TIMESTAMP}, #{record.endTime,jdbcType=TIMESTAMP}, #{record.closeTime,jdbcType=TIMESTAMP},
now(), now())
</insert>
<insert id="insertSelective" parameterType="com.aiun.order.pojo.Order" >
insert into trade_order
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="record.id != null" >
id,
</if>
<if test="record.orderNo != null" >
order_no,
</if>
<if test="record.userId != null" >
user_id,
</if>
<if test="record.shippingId != null" >
shipping_id,
</if>
<if test="record.payment != null" >
payment,
</if>
<if test="record.paymentType != null" >
payment_type,
</if>
<if test="record.postage != null" >
postage,
</if>
<if test="record.status != null" >
status,
</if>
<if test="record.paymentTime != null" >
payment_time,
</if>
<if test="record.sendTime != null" >
send_time,
</if>
<if test="record.endTime != null" >
end_time,
</if>
<if test="record.closeTime != null" >
close_time,
</if>
<if test="record.createTime != null" >
create_time,
</if>
<if test="record.updateTime != null" >
update_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="record.id != null" >
#{record.id,jdbcType=INTEGER},
</if>
<if test="record.orderNo != null" >
#{record.orderNo,jdbcType=BIGINT},
</if>
<if test="record.userId != null" >
#{record.userId,jdbcType=INTEGER},
</if>
<if test="record.shippingId != null" >
#{record.shippingId,jdbcType=INTEGER},
</if>
<if test="record.payment != null" >
#{record.payment,jdbcType=DECIMAL},
</if>
<if test="record.paymentType != null" >
#{record.paymentType,jdbcType=INTEGER},
</if>
<if test="record.postage != null" >
#{record.postage,jdbcType=INTEGER},
</if>
<if test="record.status != null" >
#{record.status,jdbcType=INTEGER},
</if>
<if test="record.paymentTime != null" >
#{record.paymentTime,jdbcType=TIMESTAMP},
</if>
<if test="record.sendTime != null" >
#{record.sendTime,jdbcType=TIMESTAMP},
</if>
<if test="record.endTime != null" >
#{record.endTime,jdbcType=TIMESTAMP},
</if>
<if test="record.closeTime != null" >
#{record.closeTime,jdbcType=TIMESTAMP},
</if>
<if test="record.createTime != null" >
#{record.createTime,jdbcType=TIMESTAMP},
</if>
<if test="record.updateTime != null" >
now(),
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.aiun.order.pojo.Order" >
update trade_order
<set >
<if test="record.orderNo != null" >
order_no = #{record.orderNo,jdbcType=BIGINT},
</if>
<if test="record.userId != null" >
user_id = #{record.userId,jdbcType=INTEGER},
</if>
<if test="record.shippingId != null" >
shipping_id = #{record.shippingId,jdbcType=INTEGER},
</if>
<if test="record.payment != null" >
payment = #{record.payment,jdbcType=DECIMAL},
</if>
<if test="record.paymentType != null" >
payment_type = #{record.paymentType,jdbcType=INTEGER},
</if>
<if test="record.postage != null" >
postage = #{record.postage,jdbcType=INTEGER},
</if>
<if test="record.status != null" >
status = #{record.status,jdbcType=INTEGER},
</if>
<if test="record.paymentTime != null" >
payment_time = #{record.paymentTime,jdbcType=TIMESTAMP},
</if>
<if test="record.sendTime != null" >
send_time = #{record.sendTime,jdbcType=TIMESTAMP},
</if>
<if test="record.endTime != null" >
end_time = #{record.endTime,jdbcType=TIMESTAMP},
</if>
<if test="record.closeTime != null" >
close_time = #{record.closeTime,jdbcType=TIMESTAMP},
</if>
<if test="record.createTime != null" >
create_time = #{record.createTime,jdbcType=TIMESTAMP},
</if>
<if test="record.updateTime != null" >
update_time = now(),
</if>
</set>
where id = #{record.id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.aiun.order.pojo.Order" >
update trade_order
set order_no = #{record.orderNo,jdbcType=BIGINT},
user_id = #{record.userId,jdbcType=INTEGER},
shipping_id = #{record.shippingId,jdbcType=INTEGER},
payment = #{record.payment,jdbcType=DECIMAL},
payment_type = #{record.paymentType,jdbcType=INTEGER},
postage = #{record.postage,jdbcType=INTEGER},
status = #{record.status,jdbcType=INTEGER},
payment_time = #{record.paymentTime,jdbcType=TIMESTAMP},
send_time = #{record.sendTime,jdbcType=TIMESTAMP},
end_time = #{record.endTime,jdbcType=TIMESTAMP},
close_time = #{record.closeTime,jdbcType=TIMESTAMP},
create_time = #{record.createTime,jdbcType=TIMESTAMP},
update_time = now()
where id = #{record.id,jdbcType=INTEGER}
</update>
<select id="selectByUserIdAndOrderNo" resultMap="BaseResultMap" parameterType="map">
select
<include refid="Base_Column_List"/>
from trade_order
where order_no = #{orderNo}
and user_id = #{userId}
</select>
<select id="selectByOrderNo" resultMap="BaseResultMap" parameterType="long">
select
<include refid="Base_Column_List"/>
from trade_order
where order_no = #{orderNo}
</select>
<select id="selectByUserId" resultMap="BaseResultMap" parameterType="int">
SELECT
<include refid="Base_Column_List"/>
FROM trade_order
WHERE user_id = #{userId}
ORDER BY create_time DESC
</select>
<select id="selectAllOrder" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM trade_order
ORDER BY create_time DESC
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.aiun.order.mapper.OrderItemMapper" >
<resultMap id="BaseResultMap" type="com.aiun.order.pojo.OrderItem" >
<constructor >
<idArg column="id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="user_id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="order_no" jdbcType="BIGINT" javaType="java.lang.Long" />
<arg column="product_id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="product_name" jdbcType="VARCHAR" javaType="java.lang.String" />
<arg column="product_image" jdbcType="VARCHAR" javaType="java.lang.String" />
<arg column="current_unit_price" jdbcType="DECIMAL" javaType="java.math.BigDecimal" />
<arg column="quantity" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="total_price" jdbcType="DECIMAL" javaType="java.math.BigDecimal" />
<arg column="create_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
<arg column="update_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
</constructor>
</resultMap>
<sql id="Base_Column_List" >
id, user_id, order_no, product_id, product_name, product_image, current_unit_price,
quantity, total_price, create_time, update_time
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from trade_order_item
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from trade_order_item
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.aiun.order.pojo.OrderItem" >
insert into trade_order_item (id, user_id, order_no,
product_id, product_name, product_image,
current_unit_price, quantity, total_price,
create_time, update_time)
values (#{record.id,jdbcType=INTEGER}, #{record.userId,jdbcType=INTEGER}, #{record.orderNo,jdbcType=BIGINT},
#{record.productId,jdbcType=INTEGER}, #{record.productName,jdbcType=VARCHAR}, #{record.productImage,jdbcType=VARCHAR},
#{record.currentUnitPrice,jdbcType=DECIMAL}, #{record.quantity,jdbcType=INTEGER}, #{record.totalPrice,jdbcType=DECIMAL},
now(), now())
</insert>
<insert id="insertSelective" parameterType="com.aiun.order.pojo.OrderItem" >
insert into trade_order_item
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="record.id != null" >
id,
</if>
<if test="record.userId != null" >
user_id,
</if>
<if test="record.orderNo != null" >
order_no,
</if>
<if test="record.productId != null" >
product_id,
</if>
<if test="record.productName != null" >
product_name,
</if>
<if test="record.productImage != null" >
product_image,
</if>
<if test="record.currentUnitPrice != null" >
current_unit_price,
</if>
<if test="record.quantity != null" >
quantity,
</if>
<if test="record.totalPrice != null" >
total_price,
</if>
<if test="record.createTime != null" >
create_time,
</if>
<if test="record.updateTime != null" >
update_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="record.id != null" >
#{record.id,jdbcType=INTEGER},
</if>
<if test="record.userId != null" >
#{record.userId,jdbcType=INTEGER},
</if>
<if test="record.orderNo != null" >
#{record.orderNo,jdbcType=BIGINT},
</if>
<if test="record.productId != null" >
#{record.productId,jdbcType=INTEGER},
</if>
<if test="record.productName != null" >
#{record.productName,jdbcType=VARCHAR},
</if>
<if test="record.productImage != null" >
#{record.productImage,jdbcType=VARCHAR},
</if>
<if test="record.currentUnitPrice != null" >
#{record.currentUnitPrice,jdbcType=DECIMAL},
</if>
<if test="record.quantity != null" >
#{record.quantity,jdbcType=INTEGER},
</if>
<if test="record.totalPrice != null" >
#{record.totalPrice,jdbcType=DECIMAL},
</if>
<if test="record.createTime != null" >
#{record.createTime,jdbcType=TIMESTAMP},
</if>
<if test="record.updateTime != null" >
now(),
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.aiun.order.pojo.OrderItem" >
update trade_order_item
<set >
<if test="record.userId != null" >
user_id = #{record.userId,jdbcType=INTEGER},
</if>
<if test="record.orderNo != null" >
order_no = #{record.orderNo,jdbcType=BIGINT},
</if>
<if test="record.productId != null" >
product_id = #{record.productId,jdbcType=INTEGER},
</if>
<if test="record.productName != null" >
product_name = #{record.productName,jdbcType=VARCHAR},
</if>
<if test="record.productImage != null" >
product_image = #{record.productImage,jdbcType=VARCHAR},
</if>
<if test="record.currentUnitPrice != null" >
current_unit_price = #{record.currentUnitPrice,jdbcType=DECIMAL},
</if>
<if test="record.quantity != null" >
quantity = #{record.quantity,jdbcType=INTEGER},
</if>
<if test="record.totalPrice != null" >
total_price = #{record.totalPrice,jdbcType=DECIMAL},
</if>
<if test="record.createTime != null" >
create_time = #{record.createTime,jdbcType=TIMESTAMP},
</if>
<if test="record.updateTime != null" >
update_time = now(),
</if>
</set>
where id = #{record.id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.aiun.order.pojo.OrderItem" >
update trade_order_item
set user_id = #{record.userId,jdbcType=INTEGER},
order_no = #{record.orderNo,jdbcType=BIGINT},
product_id = #{record.productId,jdbcType=INTEGER},
product_name = #{record.productName,jdbcType=VARCHAR},
product_image = #{record.productImage,jdbcType=VARCHAR},
current_unit_price = #{record.currentUnitPrice,jdbcType=DECIMAL},
quantity = #{record.quantity,jdbcType=INTEGER},
total_price = #{record.totalPrice,jdbcType=DECIMAL},
create_time = #{record.createTime,jdbcType=TIMESTAMP},
update_time = now()
where id = #{record.id,jdbcType=INTEGER}
</update>
<select id="getByOrderNo" resultMap="BaseResultMap" parameterType="long">
SELECT
<include refid="Base_Column_List"/>
FROM trade_order_item
WHERE order_no = #{orderNo}
</select>
<select id="getByOrderNoAndUserId" resultMap="BaseResultMap" parameterType="map">
select
<include refid="Base_Column_List"/>
from trade_order_item
where order_no = #{orderNo}
and user_id = #{userId}
</select>
<insert id="batchInsert" parameterType="list">
insert into trade_order_item (id, order_no, user_id,
product_id, product_name, product_image,
current_unit_price, quantity, total_price,
create_time, update_time)
values
<foreach collection="orderItemList" index="index" item="item" separator=",">
(
#{item.id},#{item.orderNo},#{item.userId},#{item.productId},#{item.productName},#{item.productImage},#{item.currentUnitPrice},#{item.quantity},#{item.totalPrice},now(),now()
)
</foreach>
</insert>
</mapper>
(4)数据库建表语句
CREATE TABLE `trade_order` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单id',
`order_no` bigint(20) DEFAULT NULL COMMENT '订单号',
`user_id` int(11) DEFAULT NULL COMMENT '用户id',
`shipping_id` int(11) DEFAULT NULL COMMENT '订单的地址',
`payment` decimal(20,2) DEFAULT NULL COMMENT '实际付款金额,单位是元,保留两位小数',
`payment_type` int(4) DEFAULT NULL COMMENT '支付类型,1-在线支付',
`postage` int(10) DEFAULT NULL COMMENT '运费,单位是元',
`status` int(10) DEFAULT NULL COMMENT '订单状态:0-已取消-10-未付款,20-已付款,40-已发货,50-交易成功,60-交易关闭',
`payment_time` datetime DEFAULT NULL COMMENT '支付时间',
`send_time` datetime DEFAULT NULL COMMENT '发货时间',
`end_time` datetime DEFAULT NULL COMMENT '交易完成时间',
`close_time` datetime DEFAULT NULL COMMENT '交易关闭时间',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `order_no_index` (`order_no`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `trade_order_item` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单子表id',
`user_id` int(11) DEFAULT NULL,
`order_no` bigint(20) DEFAULT NULL COMMENT '订单号',
`product_id` int(11) DEFAULT NULL COMMENT '商品id',
`product_name` varchar(100) DEFAULT NULL COMMENT '商品名称',
`product_image` varchar(500) DEFAULT NULL COMMENT '商品图片地址',
`current_unit_price` decimal(20,2) DEFAULT NULL COMMENT '生成订单时的商品单价,单位是元,保留两位小数',
`quantity` int(10) DEFAULT NULL COMMENT '商品数量',
`total_price` decimal(20,2) DEFAULT NULL COMMENT '商品总价,单位是元,保留两位小数',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `order_no_index` (`order_no`) USING BTREE,
KEY `order_no_user_id_index` (`user_id`,`order_no`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
订单表和订单详情表
2.配置文件
看一下application.yml文件
# Spring
spring:
# 服务应用名称
application:
name: backend-order
# 数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/trade?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: root
# 指定druid 连接池以及druid 连接池配置
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 1 # 初始连接数
max-active: 20 # 最大连接数
max-idle: 20 # 最大空闲
min-idle: 1 # 最小空闲
max-wait: 60000 # 最长等待时间
server:
port: 8082 # 项目访问端口
servlet:
context-path: /backend-order # 项目访问路径
# 产品图片存放地址
image:
localhost: F:/Work/imgHost/
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
instance:
hostname: localhost
# MyBatis
mybatis:
# 配置 MyBatis 数据返回类型别名(默认别名是类名)
type-aliases-package: com.aiun.order.pojo
# 配置 MyBatis Mapper 映射文件
mapper-locations: classpath:/mappers/*.xml
# MyBatis SQL 打印(方法接口所在的包,不是 Mapper.xml 所在的包)
# pagehelper
pagehelper:
helperDialect: sqlite #postgresql
reasonable: true
supportMethodsArguments: true
params: countSql
count: countSql
returnPageInfo: check
# 记录日志
logging:
config: classpath:logback-spring.xml
和前面介绍的配置选项一样。
3.Maven依赖
下面看一下Maven项目的POM文件
首先要添加父依赖
<parent>
<groupId>com.aiun</groupId>
<artifactId>BackendManageSystem</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
还需要添加公共类的依赖
<!--backend common 依赖-->
<dependency>
<groupId>com.aiun</groupId>
<artifactId>backend-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
因为会用到用户实体类,所以加了一个user的依赖
<!-- user api 依赖 -->
<dependency>
<groupId>com.aiun</groupId>
<artifactId>backend-service-user-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
还会用到product 和shipping 依赖
<!-- product api 依赖 -->
<dependency>
<groupId>com.aiun</groupId>
<artifactId>backend-service-product-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- shipping api 依赖 -->
<dependency>
<groupId>com.aiun</groupId>
<artifactId>backend-service-shipping-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
下面是完整的pom文件
<?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>BackendManageSystem</artifactId>
<groupId>com.aiun</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>backend-order</artifactId>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--backend common 依赖-->
<dependency>
<groupId>com.aiun</groupId>
<artifactId>backend-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- user api 依赖 -->
<dependency>
<groupId>com.aiun</groupId>
<artifactId>backend-service-user-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- product api 依赖 -->
<dependency>
<groupId>com.aiun</groupId>
<artifactId>backend-service-product-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- shipping api 依赖 -->
<dependency>
<groupId>com.aiun</groupId>
<artifactId>backend-service-shipping-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--config client 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<!--feign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- eureka client 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--spring boot web 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mybatis 依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- pagehelper 分页依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!--mysql 依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--druid 连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!-- lombok 依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- swagger 依赖-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!--springboot test依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
4.启动项目
启动类OrderApplication
package com.aiun.order;
/**
* 后台启动类
* @author lenovo
*/
@EnableSwagger2
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients(basePackages = {"com.aiun.product.feign", "com.aiun.user.feign", "com.aiun.shipping.feign"})
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
这里启动类多了一个@EnableFeignClients注解,这个注解主要是通过 Feign 进行微服务不同子系统之间的通信的,详细内容看后面
还是一样,先启动注册中心,然后启动用户模块,因为该模块还需要使用到收货地址和产品信息,所以还要启动产品模块和收货地址模块。
通过Google插件Talend API Test进行购物车和订单接口的测试
成功加入购物车,购物车接口没问题,下面测试订单接口:
创建订单成功!!!
到这里订单模块就完成了。