Project(10)——收货地址 - 设置默认

Project(10)——收货地址 - 设置默认

1、分析项目

当需要开发某个项目时,首先,应该分析这个项目中,需要处理哪些种类的数据!例如:用户、商品、商品类别、收藏、订单、购物车、收货地址…

然后,将以上这些种类的数据的处理排个顺序,即先处理哪种数据,后处理哪种数据!通常,应该先处理基础数据,再处理所相关的数据,例如需要先处理商品数据,才可以处理订单数据,如果多种数据之间没有明显的关联,则应该先处理简单的,再处理较难的!

则以上这些数据的处理顺序应该是:用户 > 收货地址 > 商品类别 > 商品 > 收藏 > 购物车 > 订单

当确定了数据处理顺序后,就应该分析某个用户对应的功能有哪些,以“用户”数据为例,相关功能有:注册、登录、修改密码、修改资料、上传头像…

然后,还是需要确定以上功能的开发顺序,通常,遵循 “增 > 查 > 删 > 改” 的顺序,则以上功能的开发顺序应该是:注册 > 登录 > 修改密码 > 修改资料 > 上传头像。

每个功能的开发都应该遵循 创建数据表 > 创建实体类 > 持久层 > 业务层 > 控制器层 > 前端页面

一次只解决一个问题
大问题拆成小问题

2、用户 - 注册 - 创建数据表

3、用户 - 注册 - 创建实体类

4、用户 - 注册 - 持久层

a.规划SQL语句

b.接口与抽象方法

c.配置映射

5、用户 - 注册 - 业务层

业务层的基本定位

a.规划异常

b.接口与抽象方法

c.实现类与重写方法

6、用户 - 注册 - 控制器层

a.处理异常

b.设计请求

c.处理请求

7、用户 - 注册 - 前端页面

……

收货地址 - 分析

关于收货地址的管理,涉及的功能有:增加,查看列表,修改,删除,设为默认。

以上功能的开发顺序应该是:增加 > 查看列表 > 设为默认 > 删除 > 修改

37、收货地址 - 查看列表 - 持久层

a.规划SQL语句

b.接口与抽象方法

c.配置映射

38、收货地址 - 查看列表 - 业务层

a.规划异常

b.接口与抽象方法

c.实现类与重写方法

39、收货地址 - 查看列表 - 控制器层

a.处理异常

b.设计请求

c.处理请求

40、收货地址 - 查看列表 - 前端页面

41、收货地址 - 设置默认 - 持久层

a.规划SQL语句

如果要将某收货地址设置为默认,SQL语句大致是:


UPDATE 
    t_address 
SET 
    is_default = 1, modified_user = ?, modified_time = ?
WHERE 
    aid = ?

在把某收货地址设为默认之前,应该把原来的默认地址设为非默认,可以选择把所有的收货地址设置为非默认:


UPDATE
    t_address
SET
    is_default = 0
WHERE
    uid = ?

另外,在设置默认之前,还应该检查该收货地址数据是否存在,可通过简单的查询来实现:


SELECT
    *
FROM
    t_address
WHERE
    aid = ?


并且,除了检查数据是否存在以外,还应该检查数据的归属是否正确,即该 aid对应的数据是不是当前登录的用户的数据,则查询时,应该查询 uid 字段,与用户登录后 session 中的 uid 进行对比,以判断数据归属,则查询需要调整为:


SELECT
    uid
FROM
    t_address
WHERE
    aid = ?

总结:


// 共三条 sql 语句
// 1、将所有地址设为非默认
UPDATE t_address SET is_default=0 WHERE uid=?
// 2、将指定地址设为默认
UPDATE t_address SET is_default=1, modified_user=?, modified_time=? WHERE aid=?
// 3、查询收货地址是否存在
SELECT uid FROM t_address WHERE aid=?

b.接口与抽象方法



    /**
	 * 将所有地址设为非默认
	 * @param uid 用户 uid
	 * @return 受影响的行数
	 */
	Integer updateNonDefault(Integer uid);
	
	/**
	 * 将指定地址设为默认
	 * @param aid 指定的地址 id
	 * @return 受影响的行数
	 */
	Integer updateDefault(
			@Param("aid") Integer aid, 
			@Param("modifiedUser") String modifiedUser, 
			@Param("modifiedTime") Date modifiedTime);
	
	/**
	 * 根据 aid 查询地址信息
	 * @param aid 要查询的地址的id
	 * @return 查询到的地址信息
	 */
	Address findByAid(Integer aid);


c.配置映射


    <!-- 将所有地址设置为非默认 -->
    <!-- Integer updateNonDefault(Integer uid) -->
    <update id="updateNonDefault">
        UPDATE
            t_address
        SET
            is_default=0
        WHERE
            uid=#{uid}
    </update>
    
    <!-- 将指定地址设置为默认 -->
    <!-- Integer updateDefault(Integer aid) -->
    <update id="updateDefault">
        UPDATE
            t_address
        SET
            is_default=1, modified_user=#{modifiedUser}, modified_time=#{modifiedTime}
        WHERE
            aid=#{aid}
    </update>

    <!-- 根据收货地址 aid 查询收货地址信息 -->
    <!-- Address findByAid(Integer aid) -->
    <select id="findByAid" resultType="cn.tedu.store.entity.Address">
        SELECT
            uid
        FROM
            t_address
        WHERE
            aid=#{aid}
    </select>

编写并执行单元测试:


    /**
	 * 测试将所有地址设为非默认
	 */
	@Test
	public void testUpdateNonDefault() {
		Integer uid = 7;
		Integer rows = addressMapper.updateNonDefault(uid);
		System.err.println("rows = " + rows);
	}
	
	/**
	 * 测试将指定地址设为默认
	 */
	@Test
	public void testUpdateDefault() {
		Integer aid = 1;
		String modifiedUser = "酒厂管理员";
		Date modifiedTime = new Date();
		Integer rows = addressMapper.updateDefault(aid, modifiedUser, modifiedTime);
		System.err.println("rows = " + rows);
	}
	
	/**
	 * 测试根据 aid 查询 地址信息
	 */
	@Test
	public void testFindByAid() {
		Integer aid = 1;
		Address address = addressMapper.findByAid(aid);
		System.err.println("address.uid = " + address.getUid());
	}

42、收货地址 - 设置默认 - 业务层

a.规划异常

此次操作的流程大致是:先检查收货地址数据是否存在,再检查数据归属是否正确,然后再执行修改操作。

检查数据是否存在时,可能抛出:AddressNotFoundException
检查数据归属是否正确时,可能抛出:AccessDeniedException

执行修改操作时,可能抛出:UpdateException
所以,需要事先创建原本不存在的异常类AddressNotFoundExceptionAccessDeniedException

b.接口与抽象方法

IAddressService接口中添加抽象方法:

    
    /**
	 * 设置默认收货地址
	 * @param aid 地址 aid
	 * @param uid 用户 uid
	 * @param username 用户名
	 * @throws AddressNotFoundException 地址不存在异常
	 * @throws AccessDeniedException 访问被拒绝异常
	 * @throws UpdateException 更新失败异常
	 */
    void setDefault(Integer aid, Integer uid, String username) throws AddressNotFoundException, AccessDeniedException, UpdateException;

c.实现类与重写方法

首先,将持久层的 3个新增方法复制到AddressServiceImpl业务层实现类中:


    Integer updateNonDefault(Integer uid);
	
	Integer updateDefault(Integer aid, String modifiedUser, Date modifiedTime);
	
	Address findByAid(Integer aid);

未实现的方法是报错的,先私有化实现:


    /**
	 * 设置所有地址为非默认
	 * @param uid 用户 uid
	 */
    private void updateNonDefault(Integer uid) {
    	Integer rows = addressMapper.updateNonDefault(uid);
    	if(rows == 0) {
    		throw new UpdateException("修改默认地址失败!出现未知错误,请联系系统管理员!");
    	}
    }
	
    /**
     * 设置指定地址为默认
     * @param aid 指定地址 aid
     * @param modifiedUser 修改人
     * @param modifiedTime 修改时间
     */
	private void updateDefault(Integer aid, String modifiedUser, Date modifiedTime) {
		Integer rows = addressMapper.updateDefault(aid, modifiedUser, modifiedTime);
		if(rows != 1) {
			throw new UpdateException("修改默认地址失败!出现未知错误,请联系系统管理员!");
		}
	}
	
	/**
	 * 根据地址 aid 查询地址信息
	 * @param aid 地址 aid
	 * @return 查询到的地址信息
	 */
	private Address findByAid(Integer aid) {
		return addressMapper.findByAid(aid);
	}

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

在方法前添加@Transactional注解:


    /**
	 * 设置默认地址
	 */
	@Override
	@Transactional
	public void setDefault(Integer aid, Integer uid, String username)
			throws AddressNotFoundException, AccessDeniedException, UpdateException {
		// 根据 aid 查询地址数据是否存在
		// 不存在 -- 抛出地址不存在异常
		// 判断查询结果的 uid 与 参数 uid 是否一致
		// 不一致 -- 抛出访问被拒绝异常
		
		// 将用户所有地址设为非默认
		// 将指定地址设为默认
		
		
	}

具体实现:


    /**
	 * 设置默认地址
	 */
	@Override
	@Transactional
	public void setDefault(Integer aid, Integer uid, String username)
			throws AddressNotFoundException, AccessDeniedException, UpdateException {
		// 根据 aid 查询地址数据是否存在
		// 不存在 -- 抛出地址不存在异常
		// 判断查询结果的 uid 与 参数 uid 是否一致
		// 不一致 -- 抛出访问被拒绝异常
		Address result = findByAid(aid);
		if(result == null) {
			throw new AddressNotFoundException("修改默认地址失败!该地址数据不存在!");
		}
		if(result.getUid() != uid) {
			throw new AccessDeniedException("修改默认地址失败!访问被拒绝!不允许访问他人数据!");
		}
		
		// 将用户所有地址设为非默认
		updateNonDefault(uid);
		
		// 将指定地址设为默认
		Date now = new Date();
		updateDefault(aid, username, now);
		
	}

编写并执行单元测试:


    /**
	 * 测试设置地址为默认
	 */
	@Test
	public void testSetDefault() {
		try {
			Integer aid = 2;
			Integer uid = 7;
			String username = "Gin";
			service.setDefault(aid, uid, username);
			System.err.println("OK");
		}catch(ServiceException e) {
			System.err.println(e.getClass().getName());
			System.err.println(e.getMessage());
		}
	}

43、收货地址 - 设置默认 - 控制器层

a.处理异常

需要处理AddressNotFoundExceptionAccessDeniedException

b.设计请求


请求路径:/addresses/{aid}/set_default
请求参数:@PathVariable("aid") Integer aid, HttpSession session
请求类型:POST
响应数据:JsonResult<Void>


RESTful:一种 url 的设计风格
建议风格:/resources/id/command


c.处理请求


   /**
	 * 设置默认地址
	 * @param aid 地址 aid
	 * @param session 用于获取 uid、username
	 * @return
	 */
	@RequestMapping("/{aid}/set_default")
	public JsonResult<Void> setDefault(
			@PathVariable("aid") Integer aid,
			HttpSession session){
		// 从 session 中获取 uid,username
		Integer uid = getUidFromSession(session);
		String username = getUsernameFromSession(session);
		// 调用业务层方法执行设置默认地址
		service.setDefault(aid, uid, username);
		
		// 响应
		return new JsonResult<Void>(SUCCESS);
		
	}

44、收货地址 - 设置默认 - 前端页面

address.html中,在 设为默认 的选项框中添加 onclick 属性:

在这里插入图片描述
然后再添加新的 function setDefault(aid){}
先写入 alert(aid) ,登陆后进行测试:


function setDefault(aid){
	alert(aid);
}

在这里插入图片描述

测试成功后,在function setDefault(aid){}中添加执行逻辑:


<script type="text/javascript">
$(document).ready(function(){
	showAddressList();
});

function showAddressList(){
	$.ajax({
	    ......
	    ......
	    ......
	});
}

function setDefault(aid){
	$.ajax({
		"url" : "/addresses/" + aid + "/set_default",
		"type" : "post",
		"dataType" : "json",
		"success" : function(json){
			if(json.state == 2000){
				showAddressList();
			}else{
				alert("json.message");
			}
		},
		"error" : function(){
			alert("您的登录信息已过期!请重新登录!");
		}
	});
}

</script>


---------------------------------------------------------------------------

附1:基于Spring-JDBC的事务(Transaction)

首先,事务是用于保障数据安全的,可以使得一系列的增删改操作,要么全部成功,要么全部失败!

什么情况下需要使用事务: 当某个业务涉及 2 次或更多次的增、删、改操作时,必须使用事务!例如执行 2 条Update语句,或1条 Insert 语句和 1 条 Update 语句等。

如何使用事务: 基于Spring-JDBC的编程中,只需要在业务方法之前添加@Transactional注解即可。

框架在处理事务时,大致的处理过程是:


    开启事务:begin
    try{
        执行各任务
        提交:commit
    } catch(RuntimeException) {
        回滚:rollback
    }

所以,为了保证@Transactional注解能够正常保障事务,在每次的增、删、改操作执行完成后,都必须判断受影响的行数是否是预期值,如果不是预期值,必须抛出RuntimeException或其某个子孙类的异常!

另外,@Transactional注解还可以添加在业务类之前,表示该类中所有的方法在执行时,都是有事务保障的!通常并不推荐这样处理!


    @Override
	@Transactional
	public void setDefault(Integer aid, Integer uid, String username)
			throws AddressNotFoundException, AccessDeniedException, UpdateException {
		// 根据 aid 查询地址数据是否存在
		// 不存在 -- 抛出地址不存在异常
		// 判断查询结果的 uid 与 参数 uid 是否一致
		// 不一致 -- 抛出访问被拒绝异常
		// Address result = addressMapper.findByAid(aid);
		// if(result == null) {
		// 	throw new AddressNotFoundException("修改默认地址失败!该地址数据不存在!");
		// }
		// if(result.getUid() != uid) {
		//	throw new AccessDeniedException("修改默认地址失败!访问被拒绝!不允许访问他人的数据!");
		// }
		
		// 将用户所有地址设为非默认
		updateNonDefault(uid);
		
		// 将指定地址设为默认
		Date now = new Date();
		updateDefault(aid, username, now);
		
	}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值