基于springboot的外星人电脑商城项目(四)(用户管理)

外星人电脑商城项目(四)

  • 如果需要源码,点赞+关注+留言备注邮箱,晚上统一发送
  • 外星人商城项目介绍
    • 项目背景
    • 项目功能
    • 项目技术
    • 项目模块
    • 项目要求
  • 外星人商城项目开发流程
    • 第一节 基础构建
    • 第二节 用户注册
    • 第三节 用户登录
    • 第四节 用户管理
      • 第一部分 密码修改
        • 1.修改密码-持久层
        • 2.修改密码-业务层
        • 3.修改密码-控制层
        • 4.修改密码-前端页面
      • 第二部分 个人资料
        • 1. 个人资料-持久层
        • 2. 个人资料-业务层
        • 3. 个人资料-控制层
        • 4. 个人资料-前端页面
      • 第三部分 上传头像
        • 1. 上传头像-持久层
        • 2. 上传头像-业务层
        • 3. 上传头像-控制层
        • 4. 上传头像-前端页面
    • 第五节 热销商品
    • 第六节 购物车
    • 第七节 订单
    • 第八节 商品秒杀
  • 外星人商城项目总结

如果需要源码,点赞+关注+留言备注邮箱,晚上统一发送

外星人商城项目介绍

项目背景

外星人公司(狗头)委托我开发一个一个专门的外星人商城(模仿京东、天猫),出售外星人电子产品以及周边,实现了以下功能。
本项目已经搭载了服务器,网址给定:
链接: 外星人官方网站.

项目功能

  • 登录
  • 注册
  • 用户管理
  • 热销商品
  • 购物车
  • 订单
  • 商品秒杀

项目技术

  • 项目框架:springboot
  • 数据库框架:mybaits
  • 前端技术:JS、JQuery、Ajax

项目模块

持久层:依据业务要求规划相关的SQL语句,以及进行配置
业务层:核心功能控制、业务操作以及异常处理
控制层:接受请求,处理响应
前端开发:JS、JQuery、Ajax
单元测试:junit

项目要求

  • JDK8
  • maven3.6.1
  • 数据库mysql5.1
  • idea

外星人商城项目开发流程

第一节 基础构建

第二节 用户注册

第三节 用户登录

第四节 用户管理

今天来完成新的模块
基于springboot的外星人电脑商城项目(四)(用户管理)_第1张图片

基于springboot的外星人电脑商城项目(四)(用户管理)_第2张图片

基于springboot的外星人电脑商城项目(四)(用户管理)_第3张图片

第一部分 密码修改

1.修改密码-持久层

规划内容,编写sql语句
首先,查询用户是否存在

    /**
     * 根据用户名查询用户数据
     * @param username 用户名
     * @return 匹配的用户数据,如果没有匹配的数据,则返回null
     */
    User findByUsername(String username);

    /**
     * 根据uid更新用户的密码
     * @param uid 用户的id
     * @param password 新密码
     * @param modifiedUser 最后修改执行人
     * @param modifiedTime 最后修改时间
     * @return 受影响的行数
     */
    Integer updatePasswordByUid(
            @Param("uid") Integer uid,
            @Param("password") String password,
            @Param("modifiedUser") String modifiedUser,
            @Param("modifiedTime") Date modifiedTime);
    /*
    Integer updatePasswordByUid(
            Integer uid,
            String password,
            String modifiedUser,
            Date modifiedTime); */

    <!-- 根据用户名查询用户数据:User findByUsername(String username) -->
    <select id="findByUsername" resultMap="UserEntityMap">
        SELECT
            *
        FROM
            compution.t_user
        WHERE
            username = #{username}
    </select>
    <!-- 根据uid更新用户的密码:
	     Integer updatePasswordByUid(
		    @Param("uid") Integer uid,
		    @Param("password") String password,
		    @Param("modifiedUser") String modifiedUser,
		    @Param("modifiedTime") Date modifiedTime) -->
    <update id="updatePasswordByUid">
        UPDATE
            compution.t_user
        SET
            password = #{password},
            modified_user = #{modifiedUser},
            modified_time = #{modifiedTime}
        WHERE
            uid = #{uid}
    </update>

2.修改密码-业务层

    /**
     * 修改密码
     * @param uid 当前登录的用户id
     * @param username 用户名
     * @param oldPassword 原密码
     * @param newPassword 新密码
     */
    public void changePassword(Integer uid, String username, String oldPassword, String newPassword);
    @Override
    public void changePassword(Integer uid, String username, String oldPassword, String newPassword) {
        // 调用userMapper的findByUid()方法,根据参数uid查询用户数据
        User result = userMapper.findByUid(uid);
        // 检查查询结果是否为null
        if (result == null) {
            // 是:抛出UserNotFoundException异常
            throw new UserNotFoundException("用户数据不存在");
        }

        // 检查查询结果中的isDelete是否为1
        if (result.getIsDelete().equals(1)) {
            // 是:抛出UserNotFoundException异常
            throw new UserNotFoundException("用户数据不存在");
        }

        // 从查询结果中取出盐值
        String salt = result.getSalt();
        // 将参数oldPassword结合盐值加密,得到oldMd5Password
        String oldMd5Password = getMd5Password(oldPassword, salt);
        // 判断查询结果中的password与oldMd5Password是否不一致
        if (!result.getPassword().contentEquals(oldMd5Password)) {
            // 是:抛出PasswordNotMatchException异常
            throw new PasswordNotMatchException("原密码错误");
        }

        // 将参数newPassword结合盐值加密,得到newMd5Password
        String newMd5Password = getMd5Password(newPassword, salt);
        // 创建当前时间对象
        Date now = new Date();
        // 调用userMapper的updatePasswordByUid()更新密码,并获取返回值
        Integer rows = userMapper.updatePasswordByUid(uid, newMd5Password, username, now);
        // 判断以上返回的受影响行数是否不为1
        if (rows != 1) {
            // 是:抛出UpdateException异常
            throw new UpdateException("更新用户数据时出现未知错误,请联系系统管理员");
        }
    }

3.修改密码-控制层

异常处理

        } else if (e instanceof InsertException) {
            result.setState(5000);
        } else if (e instanceof UpdateException) {
            result.setState(5001);
    @GetMapping("get_by_uid")
    public JsonResult<User> getByUid(HttpSession session) {
        // 从HttpSession对象中获取uid
        Integer uid = getUidFromSession(session);
        // 调用业务对象执行获取数据
        User data = userService.getByUid(uid);
        // 响应成功和数据
        return new JsonResult<User>(OK, data);
    }
//    public JsonResult changePassword(String oldPassword, String newPassword, HttpSession session) {
    public String changePassword(String oldPassword, String newPassword, HttpSession session) {
        // 调用session.getAttribute("")获取uid和username
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);

        // 调用业务对象执行修改密码
        userService.changePassword(uid, username, oldPassword, newPassword);
        // 返回成功
//        return new JsonResult(OK);
        return "redirect:/web/login.html";
    }

4.修改密码-前端页面

<form id="form-change-password" class="form-horizontal" role="form">
    @RequestMapping("change_password")
    
  • @RequestMapping除了可以指定URL映射外,还可以指定“请求方法、请求参数和请求头”的映射请求
  • @RequestMapping来映射URL
<!--修改密码表单开始-->
<form id="form-change-password" class="form-horizontal" role="form">
	<div class="form-group">
		<label class="col-md-2 control-label">原密码:</label>
		<div class="col-md-8">
			<input name="oldPassword" type="text" class="form-control" placeholder="请输入原密码">
		</div>
	</div>
	<div class="form-group">
		<label class="col-md-2 control-label">新密码:</label>
		<div class="col-md-8">
			<input name="newPassword" type="text" class="form-control" placeholder="请输入新密码">
		</div>
	</div>
	<div class="form-group">
		<label class="col-md-2 control-label">确认密码:</label>
		<div class="col-md-8">
			<input type="text" class="form-control" placeholder="请再次输入新密码">
		</div>
	</div>
	<div class="form-group">
		<div class="col-sm-offset-2 col-sm-10">
			<input id="btn-change-password" type="button" class="btn btn-primary" value="修改" />
		</div>
	</div>
</form>

ajax

		<!--页脚结束-->

		<script type="text/javascript">
			$("#btn-change-password").click(function() {
				$.ajax({
					url: "/users/change_password",
					type: "POST",
					data: $("#form-change-password").serialize(),
					dataType: "json",
					success: function(json) {
						if (json.state == 200) {
							alert("修改成功!");
						} else {
							alert("修改失败!" + json.message);
						}
					},
					error: function (xhr) {
						alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
						location.href = "login.html";
					}
				});
			});
		</script>

第二部分 个人资料

1. 个人资料-持久层

这里发现我对于mybatis中的判断这种不懂,需要回顾

    <!-- 根据uid更新用户个人资料:Integer updateInfoByUid(User user) -->
    <update id="updateInfoByUid">
        UPDATE
        compution.t_user
        SET
            <if test="phone != null">phone = #{phone},
            <if test="email != null">email = #{email},
            <if test="gender != null">gender = #{gender},
            modified_user = #{modifiedUser},
            modified_time = #{modifiedTime}
        WHERE
            uid = #{uid}
    </update>

2. 个人资料-业务层

    /**
     * 根据uid更新用户资料
     * @param user 封装了用户id和新个人资料的对象
     * @return 受影响的行数
     */
    Integer updateInfoByUid(User user);

    @Override
    public void changeInfo(Integer uid, String username, User user) {
        // 调用userMapper的findByUid()方法,根据参数uid查询用户数据
        User result = userMapper.findByUid(uid);
        // 判断查询结果是否为null
        if (result == null) {
            // 是:抛出UserNotFoundException异常
            throw new UserNotFoundException("用户数据不存在");
        }

        // 判断查询结果中的isDelete是否为1
        if (result.getIsDelete().equals(1)) {
            // 是:抛出UserNotFoundException异常
            throw new UserNotFoundException("用户数据不存在");
        }

        // 向参数user中补全数据:uid
        user.setUid(uid);
        // 向参数user中补全数据:modifiedUser(username)
        user.setModifiedUser(username);
        // 向参数user中补全数据:modifiedTime(new Date())
        user.setModifiedTime(new Date());
        // 调用userMapper的updateInfoByUid(User user)方法执行修改,并获取返回值
        Integer rows = userMapper.updateInfoByUid(user);
        // 判断以上返回的受影响行数是否不为1
        if (rows != 1) {
            // 是:抛出UpdateException异常
            throw new UpdateException("更新用户数据时出现未知错误,请联系系统管理员");
        }
    }

3. 个人资料-控制层

这里要进行异常处理

        } else if (e instanceof UpdateException) {
            result.setState(5001);
    @RequestMapping("change_info")
    public JsonResult<Void> changeInfo(User user, HttpSession session) {
        // 从HttpSession对象中获取uid和username
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        // 调用业务对象执行修改用户资料
        userService.changeInfo(uid, username, user);


        // 响应成功
        return new JsonResult<Void>(OK);
    }

4. 个人资料-前端页面

						<!--修改资料表单开始-->
						<form id="form-change-info" class="form-horizontal" role="form">
							<div class="form-group">
								<label class="col-md-2 control-label">用户名:</label>
								<div class="col-md-8">
									<input id="username" type="text" class="form-control" value="孙悟空" readonly="readonly">
								</div>
							</div>
							<div class="form-group">
								<label class="col-md-2 control-label">电话号码:</label>
								<div class="col-md-8">
									<input id="phone" name="phone" type="text" class="form-control" placeholder="请输入电话号码" value="13311311313">
								</div>
							</div>
							<div class="form-group">
								<label class="col-md-2 control-label">电子邮箱:</label>
								<div class="col-md-8">
									<input id="email" name="email" type="text" class="form-control" placeholder="请输入电子邮箱" value="[email protected]">
								</div>
							</div>
							<div class="form-group">
								<label class="col-md-2 control-label">性别:</label>
								<div class="col-md-8">
									<label class="radio-inline">
										<input id="gender-male" type="radio" name="gender" value="1" ></label>
									<label class="radio-inline">
										<input id="gender-female" type="radio" name="gender" value="0"></label>
								</div>
							</div>
							<div class="form-group">
								<div class="col-sm-offset-2 col-sm-10">
									<input id="btn-change-info" type="button" class="btn btn-primary" value="修改" />
								</div>
							</div>
						</form>
		<script type="text/javascript">
			$(document).ready(function() {
				$.ajax({
					url: "/users/get_by_uid",
					type: "GET",
					dataType: "json",
					success: function(json) {
						if (json.state == 200) {
							console.log("username=" + json.data.username);
							console.log("phone=" + json.data.phone);
							console.log("email=" + json.data.email);
							console.log("gender=" + json.data.gender);

							$("#username").val(json.data.username);
							$("#phone").val(json.data.phone);
							$("#email").val(json.data.email);

							let radio = json.data.gender == 0 ? $("#gender-female") : $("#gender-male");
							radio.prop("checked", "checked");
						} else {
							alert("获取用户信息失败!" + json.message);
						}
					}
				});
			});

			$("#btn-change-info").click(function() {
				$.ajax({
					url: "/users/change_info",
					type: "POST",
					data: $("#form-change-info").serialize(),
					dataType: "json",
					success: function(json) {
						if (json.state == 200) {
							alert("修改成功!");
							location.href = "login.html";
						} else {
							alert("修改失败!" + json.message);
						}
					},
					error: function(xhr) {
						alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
						location.href = "login.html";
					}
				});
			});
		</script>

第三部分 上传头像

1. 上传头像-持久层

老样子,接口和sql语句

    /**
     * 根据uid更新用户的头像
     * @param uid 用户的id
     * @param avatar 新头像的路径
     * @param modifiedUser 修改执行人
     * @param modifiedTime 修改时间
     * @return 受影响的行数
     */
    Integer updateAvatarByUid(
            @Param("uid") Integer uid,
            @Param("avatar") String avatar,
            @Param("modifiedUser") String modifiedUser,
            @Param("modifiedTime") Date modifiedTime);
    <!-- 根据uid更新用户的头像
	     Integer updateAvatarByUid(
		    @Param("uid") Integer uid,
		    @Param("avatar") String avatar,
		    @Param("modifiedUser") String modifiedUser,
		    @Param("modifiedTime") Date modifiedTime) -->
    <update id="updateAvatarByUid">
        UPDATE
            compution.t_user
        SET
            avatar = #{avatar},
            modified_user = #{modifiedUser},
            modified_time = #{modifiedTime}
        WHERE
            uid = #{uid}
    </update>

2. 上传头像-业务层

avatar:/upload/9c8dacd6-9f73-4c60-87ad-270eba65f24c.png
    /**
     * 修改用户头像
     * @param uid 当前登录的用户的id
     * @param username 当前登录的用户名
     * @param avatar 用户的新头像的路径
     */
    void changeAvatar(Integer uid, String username, String avatar);
    @Override
    public void changeAvatar(Integer uid, String username, String avatar) {
        // 调用userMapper的findByUid()方法,根据参数uid查询用户数据
        User result = userMapper.findByUid(uid);
        // 检查查询结果是否为null
        if (result == null) {
            // 是:抛出UserNotFoundException
            throw new UserNotFoundException("用户数据不存在");
        }

        // 检查查询结果中的isDelete是否为1
        if (result.getIsDelete().equals(1)) {
            // 是:抛出UserNotFoundException
            throw new UserNotFoundException("用户数据不存在");
        }

        // 创建当前时间对象
        Date now = new Date();
        // 调用userMapper的updateAvatarByUid()方法执行更新,并获取返回值
        Integer rows = userMapper.updateAvatarByUid(uid, avatar, username, now);
        // 判断以上返回的受影响行数是否不为1
        if (rows != 1) {
            // 是:抛出UpdateException
            throw new UpdateException("更新用户数据时出现未知错误,请联系系统管理员");
        }
    }

3. 上传头像-控制层

    @PostMapping("change_avatar")
    public JsonResult<String> changeAvatar(@RequestParam("file") MultipartFile file, HttpSession session) {
        // 判断上传的文件是否为空
        if (file.isEmpty()) {
            // 是:抛出异常
            throw new FileEmptyException("上传的头像文件不允许为空");
        }

        // 判断上传的文件大小是否超出限制值
        if (file.getSize() > AVATAR_MAX_SIZE) { // getSize():返回文件的大小,以字节为单位
            // 是:抛出异常
            throw new FileSizeException("不允许上传超过" + (AVATAR_MAX_SIZE / 1024) + "KB的头像文件");
        }

        // 判断上传的文件类型是否超出限制
        String contentType = file.getContentType();
        // boolean contains(Object o):当前列表若包含某元素,返回结果为true;若不包含该元素,返回结果为false
        if (!AVATAR_TYPES.contains(contentType)) {
            // 是:抛出异常
            throw new FileTypeException("不支持使用该类型的文件作为头像,允许的文件类型:" + AVATAR_TYPES);
        }

        // 获取当前项目的绝对磁盘路径
        String parent = session.getServletContext().getRealPath("upload");
        System.out.println(parent);
        // 保存头像文件的文件夹
        File dir = new File(parent);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 保存的头像文件的文件名
        String suffix = "";
        String originalFilename = file.getOriginalFilename();
        int beginIndex = originalFilename.lastIndexOf(".");
        if (beginIndex > 0) {
            suffix = originalFilename.substring(beginIndex);
        }
        String filename = UUID.randomUUID().toString() + suffix;

        // 创建文件对象,表示保存的头像文件
        File dest = new File(dir, filename);
        // 执行保存头像文件
        try {
            file.transferTo(dest);
        } catch (IllegalStateException e) {
            // 抛出异常
            throw new FileStateException("文件状态异常,可能文件已被移动或删除");
        } catch (IOException e) {
            // 抛出异常
            throw new FileUploadIOException("上传文件时读写错误,请稍后重新尝试");
        }

        // 头像路径
        String avatar = "/upload/" + filename;
        // 从Session中获取uid和username
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        // 将头像写入到数据库中
        userService.changeAvatar(uid, username, avatar);

        // 返回成功头像路径
        return new JsonResult<String>(OK, avatar);
    }

4. 上传头像-前端页面

<!--上传头像表单开始-->
<form id="form-change-avatar" class="form-horizontal" role="form">
	<div class="form-group">
		<label class="col-md-2 control-label">选择头像:</label>
		<div class="col-md-5">
			<img id="img-avatar" src="../images/index/user.jpg" class="img-responsive" />
		</div>
		<div class="clearfix"></div>
		<div class="col-md-offset-2 col-md-4">
			<input type="file" name="file">
		</div>
	</div>
	<div class="form-group">
		<div class="col-sm-offset-2 col-sm-10">
			<input id="btn-change-avatar" type="button" class="btn btn-primary" value="上传" />
		</div>
	</div>
</form>

		<script type="text/javascript">
			$(document).ready(function () {
				console.log("cookie中的avatar=" + $.cookie("avatar"));
				$("#img-avatar").attr("src", $.cookie("avatar"));
			});

			$("#btn-change-avatar").click(function() {
				$.ajax({
					url: "/users/change_avatar",
					type: "POST",
					data: new FormData($("#form-change-avatar")[0]),
					dataType: "JSON",
					processData: false, // processData处理数据
					contentType: false, // contentType发送数据的格式
					success: function(json) {
						if (json.state == 200) {
							$("#img-avatar").attr("src", json.data);
							$.cookie("avatar", json.data, {expires: 7});
						} else {
							alert("修改失败!" + json.message);
						}
					},
					error: function(xhr) {
						alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
						location.href = "login.html";
					}
				});
			});
		</script>

第五节 热销商品

第六节 购物车

第一部分 加入购物车
第二部分 显示购物车
第三部分 购物车商品数量
第四部分 勾选数据

第七节 订单

第八节 商品秒杀

外星人商城项目总结

你可能感兴趣的:(外星人官方笔记本商城,后端,spring,boot)