store(商城项目)Springboot+springmvc+ajax+mybatis(13-1)

60. 商品-显示详情-持久层

(a) 规划所需要执行的SQL语句

select * from t_product where id=?

(b) 接口与抽象方法

Product findById(Integer id);

(c) 配置映射

映射:

<!-- 根据商品id查询商品详情 -->
<!-- Product findById(Integer id) -->
<select id="findById"
    resultMap="ProductEntityMap">
    SELECT
        *
    FROM
        t_product
    WHERE
        id=#{id}
</select>

测试:

@Test
public void findById() {
    Integer id = 10000001;
    Product result = mapper.findById(id);
    System.err.println(result);
}

61. 商品-显示详情-业务层

(a) 规划可能出现的异常

创建ProductNotFoundException

(b) 业务接口及抽象方法

Product getById(Integer id);

(c) 实现抽象方法

先将持久层的方法复制到实现类,实现为私有方法:

/**
 * 根据商品id查询商品详情
 * @param id 商品id
 * @return 匹配的商品详情,如果没有匹配的数据,则返回null
 */
private Product findById(Integer id) {
    return productMapper.findById(id);
}

然后,重写接口中的抽象方法:

@Override
public Product getById(Integer id) {
    Product product = findById(id);
    if (product == null) {
        throw new ProductNotFoundException(
            "获取商口数据失败!尝试访问的数据不存在!");
    }

    product.setCategoryId(null);
    product.setPriority(null);
    product.setCreatedUser(null);
    product.setCreatedTime(null);
    product.setModifiedUser(null);
    product.setModifiedTime(null);

    return product;
}

测试:

@Test
public void getById() {
    try {
        Integer id = 10088001;
        Product result = service.getById(id);
        System.err.println(result);
    } catch (ServiceException e) {
        System.err.println(e.getClass().getName());
        System.err.println(e.getMessage());
    }
}

62. 商品-显示详情-控制器层

(a) 处理新创建的异常

处理ProductNotFoundException

(b) 设计所需要处理的请求

// http://localhost:8080/products/10000002/details
请求路径:/products/{id}/details
请求参数:@PathVariable("id") Integer id
请求方式:GET
响应结果:JsonResult<Product>

(c) 处理请求

// http://localhost:8080/products/10000002/details
@GetMapping("{id}/details")
public JsonResult<Product> getById(
    @PathVariable("id") Integer id) {
    Product data = productService.getById(id);
    return new JsonResult<>(OK, data);
}

63. 商品-显示详情-前端页面

常用的jquery函数:

  • empty():将某个标签的子级内容清空,例如<h1>xxx</h1>,如果选中该<h1>标签后调用该方法,得到的效果将是<h1></h1>

  • html():将某标签的子级设置为参数值,无视该标签原本子级内容,例如调用对某<h1>对象调用html("HAHA"),得到的效果将是<h1>HAHA</h1>

  • append():向某标签的子级追加参数值内容,例如存在<h1>HAHA</h1>,如果对该标签对象调用append("!!!"),得到的效果将是<h1>HAHA!!!</h1>

  • val():获取/设置某个表单控件的值,调用该函数时,如果没有参数,则表示获取值,如果使用了参数,则表示设置值

  • attr():设置某个标签的某个属性的值,该函数有2个参数,第1个参数表示要设置哪个属性,第2个参数表示该属性的值,例如对<img>标签调用attr("src", "http://www.tedu.cn/logo.png");就可以设置该图片标签显示的图片路径;

  • prop():设置某个标签的某个属性的值,其参数列表的意义与attr()相同,可以简单的理解为:如果某个属性的值是true/false,或该属性名与属性值相同,例如readonly="readonly",则需要调用prop()函数,如果是其它属性,则调用attr()函数;其根本是:attr()函数用于调整HTML属性,而prop()函数用于调用对象在JS中的属性。

64. 购物车-创建数据表

 

CREATE TABLE t_cart (
    cid INT AUTO_INCREMENT COMMENT '购物车数据id',
    uid INT NOT NULL COMMENT '用户id',
    pid INT NOT NULL COMMENT '商品id',
    num INT NOT NULL COMMENT '商品数量',
    price BIGINT(20) NOT NULL COMMENT '将商品添加到购物车时的价格',
    created_user VARCHAR(20) COMMENT '创建人',
    created_time DATETIME COMMENT '创建时间',
    modified_user VARCHAR(20) COMMENT '最后修改人',
    modified_time DATETIME COMMENT '最后修改时间',
    PRIMARY KEY (cid)
) DEFAULT CHARSET=utf8mb4;

65. 购物车-创建实体类

/**
 * 购物车数据的实体类
 */
public class Cart extends BaseEntity {

    private static final long serialVersionUID = -9051846958681813039L;

    private Integer cid;
    private Integer uid;
    private Integer pid;
    private Integer num;
    private Long price;

}

66. 购物车-加入购物车-持久层

(a) 规划所需要执行的SQL语句

将商品添加到购物车,向购物车数据表中添加新的数据,需要执行的SQL语句大致是:

insert into t_cart (除了cid以外的字段的列表) values (匹配的值列表);

如果是同一个用户将同一个商品重复添加到购物车中,并不会增加新的数据,而只是在原有的数据基础之上修改数量即可!需要执行的SQL语句大致是:

update t_cart set num=?, modified_user=?, modified_time=? where cid=?

既然“加入购物车”时,可能插入数据,也可能是修改数据,其判断标准应该是“该用户有没有将该商品添加到购物车”,“用户”与“商品”都是判断标准!需要执行的SQL语句大致是:

select * from t_cart where uid=? and pid=?

(b) 接口与抽象方法

创建CartMapper接口,并声明抽象方法:

/**
 * 插入购物车数据
 * @param cart 购物车数据
 * @return 受影响的行数
 */
Integer insert(Cart cart);

/**
 * 修改购物车数据中商品的数量
 * @param cid 购物车数据id
 * @param num 新的数量
 * @param modifiedUser 修改执行人
 * @param modifiedTime 修改时间
 * @return 受影响的行数
 */
Integer updateNumByCid(
    @Param("cid") Integer cid, 
    @Param("num") Integer num, 
    @Param("modifiedUser") String modifiedUser, 
    @Param("modifiedTime") Date modifiedTime);

/**
 * 根据用户id与商品id查询购物车数据
 * @param uid 用户id
 * @param pid 商品id
 * @return 匹配的购物车数据,如果没有匹配的数据,则返回null
 */
Cart findByUidAndPid(
    @Param("uid") Integer uid, 
    @Param("pid") Integer pid);

(c) 配置映射

映射:

<mapper namespace="cn.tedu.store.mapper.CartMapper">

    <resultMap id="CartEntityMap"
        type="cn.tedu.store.entity.Cart">
        <id column="cid" property="cid" />
        <result column="created_user" property="createdUser" />
        <result column="created_time" property="createdTime" />
        <result column="modified_user" property="modifiedUser" />
        <result column="modified_time" property="modifiedTime" />
    </resultMap>

    <!-- 插入购物车数据 -->
    <!-- Integer insert(Cart cart) -->
    <insert id="insert"
        useGeneratedKeys="true"
        keyProperty="cid">
        INSERT INTO t_cart (
            uid, pid,
            num, price,
            created_user, created_time,
            modified_user, modified_time
        ) VALUES (
            #{uid}, #{pid},
            #{num}, #{price},
            #{createdUser}, #{createdTime},
            #{modifiedUser}, #{modifiedTime}
        )
    </insert>

    <!-- 修改购物车数据中商品的数量 -->
    <!-- Integer updateNumByCid(
        @Param("cid") Integer cid, 
        @Param("num") Integer num, 
        @Param("modifiedUser") String modifiedUser, 
        @Param("modifiedTime") Date modifiedTime) -->
    <update id="updateNumByCid">
        UPDATE
            t_cart
        SET
            num=#{num},
            modified_user=#{modifiedUser},
            modified_time=#{modifiedTime}
        WHERE
            cid=#{cid}
    </update>

    <!-- 根据用户id与商品id查询购物车数据 -->
    <!-- Cart findByUidAndPid(
        @Param("uid") Integer uid, 
        @Param("pid") Integer pid) -->
    <select id="findByUidAndPid"
        resultMap="CartEntityMap">
        SELECT
            *
        FROM
            t_cart
        WHERE
            uid=#{uid} AND pid=#{pid}
    </select>

</mapper>

测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class CartMapperTests {

    @Autowired
    private CartMapper mapper;

    @Test
    public void insert() {
        Cart cart = new Cart();
        cart.setUid(1);
        cart.setPid(2);
        cart.setNum(3);
        cart.setPrice(4L);
        Integer rows = mapper.insert(cart);
        System.err.println("rows=" + rows);
    }

    @Test
    public void updateNumByCid() {
        Integer cid = 1;
        Integer num = 10;
        String modifiedUser = "默认管理员";
        Date modifiedTime = new Date();
        Integer rows = mapper.updateNumByCid(cid, num, modifiedUser, modifiedTime);
        System.err.println("rows=" + rows);
    }

    @Test
    public void findByAid() {
        Integer uid = 1;
        Integer pid = 2;
        Cart result = mapper.findByUidAndPid(uid, pid);
        System.err.println(result);
    }

}

67. 购物车-加入购物车-业务层

(a) 规划可能出现的异常

(b) 业务接口及抽象方法

创建ICartService接口,并添加抽象方法:

/**
 * 将商品添加到购物车
 * @param uid 当前登录的用户的id
 * @param username 当前登录的用户名
 * @param pid 商品id
 * @param amount 将商品添加到购物车中的数量
 */
void addToCart(Integer uid, String username, Integer pid, Integer amount);

(c) 实现抽象方法

创建CartServiceImpl类,实现以上接口,在类的声明之前添加@Service注解,在类中声明@Autowired private CartMapper cartMapper;持久层对象,并声明@Autowired private IProductService productService;处理商品数据的业务对象!将持久层中的3个方法复制到当前实现类中,声明为私有方法,并实现:

/**
 * 处理购物车数据的业务层实现类
 */
@Service
public class CartServiceImpl implements ICartService {

    @Autowired
    private CartMapper cartMapper;
    @Autowired
    private IProductService productService;

    @Override
    public void addToCart(Integer uid, String username, Integer pid, Integer amount) {
        // TODO Auto-generated method stub

    }

    /**
     * 插入购物车数据
     * @param cart 购物车数据
     * @return 受影响的行数
     */
    private void insert(Cart cart) {
        Integer rows = cartMapper.insert(cart);
        if (rows != 1) {
            throw new InsertException(
                "创建购物车数据失败!插入购物车数据时出现未知错误,请联系系统管理员!");
        }
    }

    /**
     * 修改购物车数据中商品的数量
     * @param cid 购物车数据id
     * @param num 新的数量
     * @param modifiedUser 修改执行人
     * @param modifiedTime 修改时间
     * @return 受影响的行数
     */
    private void updateNumByCid(Integer cid, Integer num, 
        String modifiedUser, Date modifiedTime) {
        Integer rows = cartMapper.updateNumByCid(cid, num, modifiedUser, modifiedTime);
        if (rows != 1) {
            throw new InsertException(
                "更新商品数量失败!更新购物车数据时出现未知错误,请联系系统管理员!");
        }
    }

    /**
     * 根据用户id与商品id查询购物车数据
     * @param uid 用户id
     * @param pid 商品id
     * @return 匹配的购物车数据,如果没有匹配的数据,则返回null
     */
    private Cart findByUidAndPid(Integer uid, Integer pid) {
        return cartMapper.findByUidAndPid(uid, pid);
    }

}

然后,重写抽象方法:

public void addToCart(Integer uid, String username, Integer pid, Integer amount) {
    // 创建当前时间对象
    // 根据uid和pid查询购物车数据
    // 判断查询结果是否为null
    // 是:表示该用户尚未将该商品添加到购物车,则需要插入购物车数据
    // -- 调用productService.getById()方法查询商品数据
    // -- 创建Cart对象
    // -- 补全数据:uid, pid, num, price(从商品数据中获取)
    // -- 补全数据:4个日志
    // -- 调用insert(cart)执行插入数据
    // 否:表示该用户已经将该商品添加到购物车,则需要修改购物车数据中商品的数量
    // -- 从查询结果中获取cid
    // -- 从查询结果中获取num,与参数amount相加,得到新的数量
    // -- 调用updateNumByCid(cid, num, modifiedUser, modifiedTime)方法执行修改数量
}

实现代码:

@Override
public void addToCart(Integer uid, String username, Integer pid, Integer amount) {
    // 创建当前时间对象
    Date now = new Date();
    // 根据uid和pid查询购物车数据
    Cart result = findByUidAndPid(uid, pid);
    // 判断查询结果是否为null
    if (result == null) {
        // 是:表示该用户尚未将该商品添加到购物车,则需要插入购物车数据
        // 调用productService.getById()方法查询商品数据
        Product product = productService.getById(pid);
        // 创建Cart对象
        Cart cart = new Cart();
        // 补全数据:uid, pid, num, price(从商品数据中获取)
        cart.setUid(uid);
        cart.setPid(pid);
        cart.setNum(amount);
        cart.setPrice(product.getPrice());
        // 补全数据:4个日志
        cart.setCreatedUser(username);
        cart.setCreatedTime(now);
        cart.setModifiedUser(username);
        cart.setModifiedTime(now);
        // 调用insert(cart)执行插入数据
        insert(cart);
    } else {
        // 否:表示该用户已经将该商品添加到购物车,则需要修改购物车数据中商品的数量
        // 从查询结果中获取cid
        Integer cid = result.getCid();
        // 从查询结果中获取num,与参数amount相加,得到新的数量
        Integer num = result.getNum() + amount;
        // 调用updateNumByCid(cid, num, modifiedUser, modifiedTime)方法执行修改数量
        updateNumByCid(cid, num, username, now);
    }
}

测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class CartServiceTests {

    @Autowired
    private ICartService service;

    @Test
    public void addToCart() {
        try {
            Integer uid = 1;
            Integer pid = 10000002;
            Integer amount = 30;
            String username = "土豪";
            service.addToCart(uid, username, pid, amount);
            System.err.println("OK.");
        } catch (ServiceException e) {
            System.err.println(e.getClass().getName());
            System.err.println(e.getMessage());
        }
    }

}

68. 购物车-加入购物车-控制器层

(a) 处理新创建的异常

(b) 设计所需要处理的请求

请求路径:/carts/add_to_cart
请求参数:Integer pid, Integer num, HttpSession session
请求方式:POST
响应结果:JsonResult<Void>

(c) 处理请求

/**
 * 处理购物车相关请求的控制器类
 */
@RestController
@RequestMapping("carts")
public class CartController extends BaseController {

    @Autowired
    private ICartService cartService;

    // http://localhost:8080/carts/add_to_cart?pid=10000005&amount=3
    @RequestMapping("add_to_cart")
    public JsonResult<Void> addToCart(
        Integer pid, Integer amount, HttpSession session) {
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        cartService.addToCart(uid, username, pid, amount);
        return new JsonResult<>(OK);
    }

}

69. 购物车-加入购物车-前端页面

使用$.ajax()处理异常请求时,关于data属性的值,可以是:

  • $("#表单id").serialize():适用于表单控件较多的应用场景;

  • "参数1=值1&参数2=值2&参数3=值3":适用于需要提交的参数较少,且字符串的拼接较简单的应用场景;

  • { "参数1":值1, "参数2":值2, "参数3":值3 }:适用于需要提交的参数较少,但是字符串的拼接较麻烦的应用场景;

  • new FormData($("#表单id")[0]):仅适用于文件上传,且需要与processDatacontentType属性一起使用。

70. 【作业】购物车-显示列表-持久层

(a) 规划所需要执行的SQL语句

显示购物车列表时,只会显示当前登录的用户的购物车数据,需要执行的SQL语句大致是:

select 
    cid, uid, pid, t_cart.num, t_cart.price,
    title, t_product.price AS realPrice, image
from 
    t_cart 
left join 
    t_product 
on 
    t_cart.pid=t_product.id
where 
    uid=?
order by 
    t_cart.created_time desc

(b) 接口与抽象方法

cn.tedu.store包中创建子级的vo包,并在这个包中创建CartVO类:

public class CartVO implements Serializable {
    private Integer cid;
    private Integer uid;
    private Integer pid;
    private Integer num;
    private String title;
    private String image;
    private Long price;
    private Long realPrice;
    // SET/GET/基于cid的hashCode和equals/toString
}

CartMapper中添加:

List<CartVO> findVOByUid(Integer uid);

(c) 配置映射

映射:

<select id="xx" resultType="cn.tedu.store.vo.CartVO">

</select>

测试:

...

71. 【作业】购物车-显示列表-业务层

(a) 规划可能出现的异常

(b) 业务接口及抽象方法

(c) 实现抽象方法

72. 【作业】购物车-显示列表-控制器层

(a) 处理新创建的异常

(b) 设计所需要处理的请求

请求路径:
请求参数:
请求方式:
响应结果:JsonResult<?>

(c) 处理请求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饭九钦vlog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值