• SpringBoot项目--电脑商城【收货地址列表展示和设置默认地址】


    1.收货地址列表展示

    1.1 持久层[Mapper]

    a. 规划需要执行的SQL语句

    数据库数据的查询操作

    select * from t_address where uid ? order by is_default DESC,created_time DESC
    

    其中order by is_default DESC是为了让默认收货地址展示在最上面,order by可以有多个字句,中间用逗号隔开,后面加的create_time DESC是为了让非默认收货地址创建的越晚越展示在上面

    b.设计接口和抽象方法

    在AddressMapper接口追加抽象方法findByUid

    1. /**
    2. * 根据用户的id查询用户的收货地址数据
    3. * @param id
    4. * @return 收货地址数据
    5. */
    6. List
      findByUid(Integer id);

    c.编写映射

    1. <select id="findByUid" resultMap="AddressEntityMap">
    2. select * from t_address where uid=#{uid}
    3. order by is_default desc ,created_time desc
    4. select>

    d.单元测试

    1. @Test
    2. public void findByUid () {
    3. List
      list = addressMapper.findByUid(11);
    4. System.out.println(list);
    5. }

    1.2 业务层[Service]

    a.规划异常

    该模块只是为了展示列表,不涉及到增删改,即便没有拿到任何数据,那无非就是不展示呗,所以不涉及到异常,不需要在业务层抛出异常

    b.设计接口和抽象方法及实现

    1.定义抽象方法

    1. /**
    2. * 获取uid对应用户的所有地址信息,用于展示
    3. * @param uid 用户uid
    4. 48 * @return 地址信息list
    5. */
    6. List
      getByUid(Integer uid);

    2.实现该方法

    1. /**
    2. * 获取uid对应用户的所有地址信息,用于展示
    3. *
    4. * @param uid 用户uid
    5. * @return 地址信息list
    6. */
    7. @Override
    8. public List
      getByUid(Integer uid) {
    9. List
      list = addressMapper.findByUid(uid);
    10. for (Address address :list){
    11. //因为就只需要展示4条数据,则将其他不用的不展示
    12. //address.setUid(null);
    13. //address.setAid(null);
    14. address.setProvinceName(null);
    15. address.setProvinceCode(null);
    16. address.setCityName(null);
    17. address.setCityCode(null);
    18. address.setAreaName(null);
    19. address.setAreaCode(null);
    20. address.setZip(null);
    21. address.setPhone(null);
    22. address.setTel(null);
    23. address.setCreatedTime(null);
    24. address.setIsDefault(null);
    25. address.setCreatedUser(null);
    26. address.setModifiedTime(null);
    27. address.setModifiedUser(null);
    28. }
    29. return list;
    30. }

    c.单元测试

    这里省略

    1. 3.控制层[controller]

    a. 处理异常

    因为业务层没有抛出异常,所以这里不需要处理异常

    b. 设计请求

    • /addresses
    • HttpSession session
    • get(该功能模块只需要uid,不需要别的数据,而且uid也是在后端封装的,所以前端没有提交什么数据,体量很小可以用get)
    • JsonResult>

    c.处理请求

    1. /**
    2. * 根据用户id展示用户已经填写的地址数据
    3. *
    4. * @param session
    5. * @return
    6. */
    7. @GetMapping({"", ""})
    8. public JsonResult> getByUid(HttpSession session) {
    9. Integer uid = getuidFromSession(session);
    10. List
      data = addressService.getByUid(uid);
    11. return new JsonResult<>(OK, data);
    12. }

    1.4 前端页面

    在address.html中编写js代码

    2.设置默认地址

    2.1 持久层[Mapper]

    a. 规划需要执行的SQL语句

    无论选择的是哪一条数据,都把所有的数据设为非默认,再把当前数据设为默认

    我们可能会想着把第一条设为非默认,再将该条设为默认,但这样处理的话需要额外做一条查询语句拿到默认地址的数据

    1.检测当前用户想设置为默认收货地址的这条数据是否存在

    select * from t_address where aid=?
    

    2.在修改用户的默认收货地址之前先将所有的收货地址设置为非默认

    update t_address set is_default=0 where uid=?
    

    3.将用户选中的这条记录设置为默认收货地址

    update t_address set is_default=1,modified_user=?,modified_time=? where aid=?
    

    b.设计接口和抽象方法

    在AddressMapper接口中来定义实现该模块所需的三个方法

    1. /**
    2. * 根据aid查询收货地址数据
    3. * @param aid 收货地址aid
    4. * @return 收货地址数据,如果没有找到则返回null值
    5. */
    6. Address findByAid(Integer aid);
    7. /**
    8. * 根据用户uid修改用户的收货地址统一设置为非默认
    9. * @param uid 用户uid
    10. * @return 受影响的行数
    11. */
    12. Integer updateNonDefault(Integer uid);
    13. Integer updateDefaultByAid(
    14. @Param("aid") Integer aid,
    15. @Param("modifiedUser") String modifiedUser,
    16. @Param("modifiedTime") Date modifiedTime);

    c.编写映射

    在AddressMapper.xml中编写映射

    1. <select id="findByAid" resultMap="AddressEntityMap">
    2. select * from t_address where aid=#{aid}
    3. select>
    4. <update id="updateNonDefault">
    5. update t_address
    6. set is_default=0
    7. where uid=#{uid}
    8. update>
    9. <update id="updateDefaultByAid">
    10. update t_address
    11. set is_default=1,
    12. modified_user=#{modifiedUser},
    13. modified_time=#{modifiedTime}
    14. where aid=#{aid}
    15. update>

    d.单元测试

    1. @Test
    2. public void findByAid() {
    3. System.err.println(addressMapper.findByAid(9));
    4. }
    5. @Test
    6. public void updateNonDefault() {
    7. System.out.println(addressMapper.updateNonDefault(11));//有几条数据影响行数就输出几
    8. }
    9. @Test
    10. public void updateDefaultByAid() {
    11. addressMapper.updateDefaultByAid(9,"明明",new Date());
    12. }

    2.业务层[Service]

    1规划异常

    • 在执行更新时产生未知的UpdateException异常,已经创建无需重复创建
    • 访问的数据不是当前登录用户的收货地址数据,属于非法访问,AccessDeniedException异常(就比如说,展示收货地址列表的sql语句写错了,然后这里展示的是别人的收货地址,此时想要将某个收货地址改为默认就属于非法访问了)
    • 收货地址可能不存在的AddressNotFoundException异常,(比如,刚展示完收货地址列表,管理员误删地址了,此时地址就不存在了)

    在业务层的ex包下创建如下两个异常类,并使其继承ServiceException类

    1. /**收货地址数据不存在的异常*/
    2. public class AddressNotFoundException extends ServiceException {
    3. /**重写ServiceException的所有构造方法*/
    4. }
    1. /**非法访问的异常*/
    2. public class AccessDeniedException extends ServiceException {
    3. /**重写ServiceException的所有构造方法*/
    4. }

    2设计接口和抽象方法及实现

    1.在IAddressService接口中编写抽象方法setDefault,并使其在方法内部统一实现持久层的三个方法

    分析一下该方法需要什么参数:

    先看持久层的三个方法需要什么参数:aid,uid,modifiedUser,modifiedTime.

    其中aid是从前端一步一步传到业务层的,所以需要该参数

    uid和modifiedUser是一样的,都是由控制层从session获取的uid并传给业务层,所以需要该参数

    modifiedTime可以在业务层new Date,所以不需要该参数

    1. /**
    2. * 修改某个用户的某条收货地址数据为默认收货地址
    3. * @param aid 收货地址的id
    4. * @param uid 用户id
    5. * @param username 修改执行人
    6. */
    7. void setDefault(Integer aid,Integer uid,String username);

    2.在AddressServiceImpl类编写该方法的实现

    1. @Override
    2. public void setDefault(Integer aid, Integer uid, String username) {
    3. //1.检测是否有该条收货地址数据
    4. Address result = addressMapper.findByAid(aid);
    5. if (result == null) {
    6. throw new AddressNotFoundException("收货地址不存在");
    7. }
    8. //2.检测当前获取到的收货地址数据的归属
    9. if (!result.getUid().equals(uid)) {
    10. throw new AccessDeniedException("非法数据访问");
    11. }
    12. //3.先将所有的收货地址设置为非默认
    13. Integer rows = addressMapper.updateNonDefault(uid);
    14. if (rows < 1) {
    15. throw new UpdateException("更新数据时产生未知的异常");
    16. }
    17. //4.将用户选中的地址设置为默认收货地址
    18. rows = addressMapper.updateDefaultByAid(aid, username, new Date());
    19. if (rows != 1) {
    20. throw new UpdateException("更新数据时产生未知的异常");
    21. }
    22. }

    3单元测试

    在AddressServiceTests类中编写单元测试方法

    1. @Test
    2. public void setDefault() {
    3. addressService.setDefault(9,11,"管理员");
    4. }

    3.控制层[controller]

    1处理异常

    在BaseController类中处理业务层抛出的两个异常

    1. else if (e instanceof AddressNotFoundException) {
    2. result.setState(4004);
    3. result.setMessage("用户的收货地址数据不存在的异常");
    4. } else if (e instanceof AccessDeniedException) {
    5. result.setState(4005);
    6. result.setMessage("收货地址数据非法访问的异常");
    7. }

    2设计请求

    • /addresses/{aid}/set_default(以前的数据是通过表单直接提交的,还有一种提交方式就是RestFul风格,这种提交方式可以提交更多的数据,这里用这个提交方式)
    • GET
    • Integer aid,HttpSession session(如果这里是id那就必须在Integer aid前加@PathVariable(“aid”)强行将aid的值注入到id中)
    • JsonResult

    3处理请求

    在AddressController类中编写请求处理方法.

    RestFul编写时不管参数名和占位符是否一致都必须加@PathVariable(“aid”)

    1. //RestFul风格的请求编写
    2. @RequestMapping("{aid}/set_default")
    3. public JsonResult setDefault(
    4. @PathVariable("aid") Integer aid,HttpSession session) {
    5. addressService.setDefault(
    6. aid,
    7. getUidFromSession(session),
    8. getUsernameFromSession(session));
    9. return new JsonResult<>(OK);
    10. }

    4.前端页面

    观察address.html代码发现"设为默认"按钮没有id属性,那应该怎么获取"设为默认"按钮以监听是否被点击了呢?

    给"设置默认"按钮添加一个onclick属性,指向一个方法的调用,在这个方法中来完成ajax请求的方法

    1.展示用户收货地址数据列表的js函数中用for循环给页面增加地址数据的tr标签,我们需要在for循环中为每一个tr标签增加onclick属性并指向setDefault(#{aid})函数,括号里面占位符是为了给外部的setDefault函数传参,可以随便写,只要给占位符赋值时对应就可以了,.注意,即使调用的是无参函数也要加括号

    <td><a onclick="setDefault(#{aid})" class="btn btn-xs add-def btn-default">设为默认a>td>
    

    2.在for循环中为占位符赋值:

    tr = tr.replace("#{aid}",list[i].aid);
    

    3.完成setDefault方法的声明

    1. function setDefault(aid) {
    2. $.ajax({
    3. url: "/addresses/"+aid+"/set_default",
    4. type: "POST",
    5. //data: $("#form-change-password").serialize(),
    6. dataType: "JSON",
    7. success: function (json) {
    8. if (json.state == 200) {
    9. //重新加载收货地址列表页面
    10. showAddressList();
    11. } else {
    12. alert("设置默认收货地址失败")
    13. }
    14. },
    15. error: function (xhr) {
    16. alert("设置默认收货地址时产生未知的异常!"+xhr.message);
    17. }
    18. });
    19. }

  • 相关阅读:
    安全可靠的文件传输服务助力完成更高效的医疗保健工作(下)
    C++中使用boost库存取ini结构化文本文件
    『从零开始学小程序』媒体组件audio组件
    高级深入--day28
    react,Chart
    如何创建多语言WordPress网站[专家建议]
    100114. 元素和最小的山形三元组 II
    设计模式:责任链模式
    高精度RC振荡器的设计
    类和对象(封装)
  • 原文地址:https://blog.csdn.net/m0_63077733/article/details/132811512