Store网上商城项目
用户注册
1 创建数据表
2 创建用户的实体类
3 注册-持久层
3.1 规划需要执行
1.用户的注册功能。相当于在做数据的插入操作- insert into t_user (username,password) values (值列表)
复制代码 2.在用户注册时要首先去查询当前的用户名是否存在,如果存在则不能进行注册。相当于是一条查询语句- select * from t_user where username=?
复制代码 3.2 设计接口和抽象方法
定义Mapper接口。在项目的目录下创建mapper包,在这个包下根据不同的功能模块来创建mapper接口。创建一个UserMapper的接口。要在接口中定义这两个抽象方法。- public interface UserMapper {
- /**
- * 插入用户的数据
- * @param user 用户的数据
- * @return 受影响的行数(增,删,改,都用受影响行数作为返回值)
- */
- Integer insert(User user);
- /**
- * 根据用户名来查询用户的数据
- * @param username 用户名
- * @return 如果找到对应的用户则返回这个用户的数据,如果没有则返回null
- */
- User findByUsername(String username);
- }
复制代码 3.3 编写映射
1.定义xml映射文件,与对应的接口进行关联。所有的映射文件需要放在resources目录下,在这个目录下创建一个mapper文件夹,然后在这个文件夹下存放Mapper映射文件
2.创建接口对应的映射文件,遵循和接口的名称保存一致即可。创建一个UserMapper.xml文件。
3.配置接口中的方法对应上SQL语句上。需要借助标签来完成,insert\update\delete\select,对应的是SQL语句的增删改查操作。
4.resultMap 定义匹配不同命名规则的属性,并把resultMap的id传入到标签的resultMap属性里面- <?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.cy.store.mapper.UserMapper">
- <resultMap id="UserEntityMap" type="com.cy.store.entity.User">
- <id column="uid" property="uid"></id>
- <result column="is_delete" property="isDelete"></result>
- <result column="created_user" property="createdUser"></result>
- <result column="created_time" property="createdTime"></result>
- <result column="modified_user" property="modifiedUser"></result>
- <result column="modified_time" property="modifiedTime"></result>
- </resultMap>
- <insert id="insert" useGeneratedKeys="true" keyProperty="uid">
- INSERT INTO t_user(username, password, salt, phone, email, gender, avatar, isDelete,createdUser, createdTime, modifiedUser, modifiedTime)
- VALUES (#{username}, #{password}, #{salt}, #{phone}, #{email}, #{gender}, #{avatar}, #{isDelete},#{createdUser}, #{createdTime}, #{modifiedUser}, #{modifiedTime})
- </insert>
- <select id="findByUsername" resultMap="UserEntityMap">
- SELECT *
- FROM t_user
- WHERE username = #{username}
- </select>
- </mapper>
复制代码 3.4 单元测试
每个独立的层编写完毕后都需要写单元测试方法,来测试当前功能。在test包结构下创建一个mapper包,在这个包下再创建持久层的功能测试。- @SpringBootTest
- @RunWith(SpringRunner.class)
- public class UserMapperTests {
- @Autowired
- private UserMapper userMapper;
- @Test
- public void insert() {
- User user = new User();
- user.setUsername("tim");
- user.setPassword("123");
- Integer rows = userMapper.insert(user);
- System.out.println(rows);
- }
- @Test
- public void findByUsername(){
- User user = userMapper.findByUsername("tim");
- System.out.println(user);
- }
- }
复制代码 4 注册-业务层
4.1 规划异常
1.RuntimeException异常:作为这类异常的子类,然后再去定义具体的异常类型来继承这个异常。业务层异常的基类,ServiceException异常。这个异常继承RuntimeException异常。异常机制的建立。- public class ServiceException extends RuntimeException{
- public ServiceException() {
- super();
- }
- public ServiceException(String message) {
- super(message);
- }
- public ServiceException(String message, Throwable cause) {
- super(message, cause);
- }
- public ServiceException(Throwable cause) {
- super(cause);
- }
- protected ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
- super(message, cause, enableSuppression, writableStackTrace);
- }
- }
复制代码根据业务层不同的功能来详细定义具体的异常的类型,统一的去继承ServiceException异常类。
2.业务异常:用户在进行注册时候可能会产生用户名被占用的错误,抛出一个异常:UsernameDepulitedException异常- public class UsernameDuplicatedException extends ServiceException{
- public UsernameDuplicatedException() {
- super();
- }
- public UsernameDuplicatedException(String message) {
- super(message);
- }
- public UsernameDuplicatedException(String message, Throwable cause) {
- super(message, cause);
- }
- public UsernameDuplicatedException(Throwable cause) {
- super(cause);
- }
- protected UsernameDuplicatedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
- super(message, cause, enableSuppression, writableStackTrace);
- }
- }
复制代码 3.其他异常:正在执行数据插入操作的时候,服务器宕机。处于正在执行插入的过程中所产生的异常InsertException
4.2 设计接口和抽象方法
1.在service包下创建一个IUserService接口。- public interface IUserService {
- /**
- * 用户注册方法
- * @param user 用户的数据对象
- */
- void reg(User user);
- }
复制代码 2.创建一个实现类UserServiceImpl类,需要实现这个接口,并且实现抽象方法- @Service
- public class UserServiceImpl implements IUserService {
- @Autowired
- private UserMapper userMapper;
- @Override
- public void reg(User user) {
- String username = user.getUsername();
- User result = userMapper.findByUsername(username);
- if (result != null){
- throw new UsernameDuplicatedException("用户名被占用");
- }else {
- String oldPassword =user.getPassword();
- String salt = UUID.randomUUID().toString().toUpperCase();
- String md5Password = getMD5Password(oldPassword, salt);
- user.setPassword(md5Password);
- user.setSalt(salt);
- user.setIsDelete(0);
- user.setCreatedUser(user.getUsername());
- user.setModifiedUser(user.getUsername());
- Date date = new Date();
- user.setCreatedTime(date);
- user.setModifiedTime(date);
- Integer rows = userMapper.insert(user);
- if(rows != 1){
- throw new InsertException("在用户注册过程中产生了未知异常");
- }
- }
- }
- private String getMD5Password(String password,String salt){
- for (int i = 0; i < 3; i++) {
- password=DigestUtils.md5DigestAsHex((salt+password+salt).getBytes(StandardCharsets.UTF_8)).toUpperCase();
- }
- return password;
- }
- }
复制代码 3.在单元测试包下创建一个UserServiceTests类,在这个类中添加单元测试的功能。- @SpringBootTest
- @RunWith(SpringRunner.class)
- public class UserServiceTests {
- @Autowired
- private IUserService userService;
- @Test
- public void reg(){
- try {
- User user=new User();
- user.setUsername("yuanxin03");
- user.setPassword("123");
- userService.reg(user);
- System.out.println("ok");
- }catch (ServiceException e){
- System.out.println(e.getClass().getSimpleName());
- System.out.println(e.getMessage());
- }
- }
- }
复制代码 5 注册-控制层
5.1 创建响应
状态码,状态描述信息,数据。这部分功能封装在一个类中,将这类作为方法返回值,返回给前端浏览器。- public class JsonResult<E> implements Serializable {
- // 状态码
- private Integer state;
- // 描述信息
- private String message;
- // 数据
- private E data;
- }
复制代码 5.2 设计请求
根据当前的业务功能模块,进行请求的设计- 请求路径:/users/reg
- 请求参数:User user
- 请求类型:Post
- 请求结果:JsonResult<void>
复制代码 5.3 处理请求
1.创建控制层对应的类UserController类,依赖于业务层的接口。
2.异常捕获
5.4 控制层优化设计
在控制层抽离父类,在这个父类中统一的去处理关于异常的相关操作。编写一个BaseController类,统一处理异常。
6 注册-前端页面
1.在register页面中编写发送请求的方法,点击事件来完成。选中对应的按钮(\(("选择器")),再去添加点击的事件,\).ajax()函数发送异步请求。
2.JQuery封装了一个函数,称之为$ajax()函数,通过对象调用ajax()函数,可以异步加载相关的请求。依靠的是JavaScript提供的一个对象XHR(XmlHttpResponse),封装了这个对象。
3.ajax()的使用方式。需要传递一个方法体作为方法的参数来使用:- $.ajax({
- url:"",
- type:"",
- data:"",
- dataType:"",
- success:function(){
-
- },
- error:function(){
-
- }
- });
复制代码 4.ajax()函数参数的含义:
5.js代码可以独立在一个js的文件里或声明在一个script标签中
用户登录
1 登录-持久层
1.1 规划需要执行的SQL语句
依据用户提交的用户名和密码做select查询。- select * from t_user where username=?
复制代码 1.2 接口设计和方法
2 登录-业务层
2.1 规划异常
1.用户名对应的密码错误,密码匹配失败的异常:PasswordNotMatchException,运行时异常,业务异常。
2.用户名没有找到:UsernameNotFoundException,运行时异常,业务异常。
3.异常的编写
2.2 设计业务层接口和抽象方法
1.直接在IUserService接口中编写抽象方法,login(String username,String password)。将当前登录成功的用户数据以当前用户对象的形式返回。状态管理:可以将数据保存在cookie或者session中,可以避免重复度很高的数据多次频繁操作数据进行获取(用户id-在session中,用户的头像-cookie中)。
2.在实现类中实现父接口的抽象方法
3.在测试类中测试业务层登录的方法是否可以执行通过。
4.如果一个类没有手动创建直接将这个类复制到项目,idea找不到这个类。解决:重新构建
2.3 抽象方法实现
3 登录-控制层
3.1 处理异常
业务层抛出的异常是什么,需要在统一异常处理类中进行统一的捕获和处理,如果业务层抛出的异常类型在已经在统一异常处理类中曾经处理过,则不需要重复处理
3.2 设计请求
- 请求路径:/users/login
- 请求参数:String username, String password
- 请求类型:Post
- 请求结果:JsonResult<User>
复制代码 3.3 处理请求
在UserController类中编写处理请求的方法。- @RequestMapping("/login")
- public JsonResult<User> login(String username,String password){
- User login = userService.login(username, password);
- return new JsonResult<>(OK,login);
- }
复制代码 4 登录-前端页面
1.在login.html页面中依据前面所设置的请求来发送ajax请求。
2.访问页面进行用户的登录操作。
用户会话session
session对象主要存在服务器端,可以用于保存服务器的临时数据的对象,所保存的数据可以在整个项目中都可以通过访问来获取,把session的数据看作一个共享的数据源。首次登陆的时候所获取的用户数据,转移到session对象即可。
session.getAttrbute("key")可以将获取session中的数据的这种行为进行封装,封装在BaseController类中。
- 封装session对象中数据的获取,数据的设置。(用户登录成功后,进行数据的设置,设置到全局的session对象)
- 在父类中封装两个数据:获取uid和获取username对应的两个方法。用户头像暂不考虑,封装在cookie中
- 在登录的方法中将数据封装在session对象中。服务器本身自动创建有session对象,已经是一个全局的session对象。SpringBoot直接使用session对象,直接将HttpSession类型的对象作为请求处理方法的参数,会自动将全局的session对象注入到请求处理方法的session形参上
- @RequestMapping("/login")
- public JsonResult<User> login(String username, String password, HttpSession session){
- User login = userService.login(username, password);
- session.setAttribute("uid",login.getUid());
- session.setAttribute("username",login.getUsername());
- System.out.println(getUidFromSession(session));
- System.out.println(getUsernameFromSession(session));
- return new JsonResult<>(OK,login);
- }
复制代码 拦截器
拦截器:首先将所有的请求统一拦截到拦截器中,开发者可以在拦截器中定义过滤的规则,如果不满足系统的设置的过滤规则,统一的处理是重新去打开login.html页面(重定向和转发),推荐使用重定向。
在SpringBoot项目中实现拦截器的定义和使用。SpringBoot是依靠SpringMVC来完成的。SpringMVC提供了一个接口HandlerInterceptor接口,用于表示定义一个拦截器。首先,自定义一个类,再用这个类去实现这个接口。
1.自定义一个类,用这个类实现HandlerInterceptoer接口。- /**
- * 定义一个拦截器
- */
- public class LoginInterceptor implements HandlerInterceptor {
- /**
- * 检测全局session对象中是否有uid数据,如果有则放行,如果没有则重定向到登录页面
- * @param request 请求对象
- * @param response 响应对象
- * @param handler 处理器
- * @return 如果返回值为true表示放行当前的请求,如果返回值为false则表示拦截当前的请求
- * @throws Exception
- */
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- Object uid = request.getSession().getAttribute("uid");
- if (uid==null){
- response.sendRedirect("/web/login.html");
- return false;
- }
- return true;
- }
- }
复制代码 2.注册过滤器:添加白名单(哪些资源可以在不登录的情况下访问:login.html\register.html\login\reg\index.html\product.html)、添加黑名单(登录时才可以访问的页面资源)
3.注册过滤技术:借助WebMvcConfigure接口,可以将用户定义的拦截器进行注册,才可以保证拦截器能够生效和使用。定义一个类,然后让这个类实现WebMvcConfigure接口。配置信息,建议存放在项目的config包结构下。- public class LoginInterceptorConfigurer implements WebMvcConfigurer {
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- WebMvcConfigurer.super.addInterceptors(registry);
- }
- }
复制代码 修改密码
需要用户提交原始密码和新密码,再根据当前登录的用户进行信息的修改操作。
1 修改密码-持久层
1.1 规划需要执行的SQL语句
根据用户的uid修改用户的password值。- update t_user set password=?,modified_user?=modified_time=?where uid=?
复制代码 根据uid查询用户的数据。在修改密码之前,首先要保证当前这用户的数据存在(is_delete),检测是否被标记为删除、检测输入的原始密码是否正确。- select * from t_user where uid=?
复制代码 1.2 UserMapper接口定义方法
1.3 UserMapper.xml完善SQL语句
1.4 单元测试
2 修改密码-业务层
2.1 规划可能产生的异常
1 用户输入的原密码错误 PasswordNotMatch异常
2 用户已删除
3 uid找不到用户
4 update更新时产生的未知的异常,UpadateException
2.2 设计接口和抽象方法
执行用户修改密码的核心方法
2.3 编写单元测试
3 修改密码-控制层
3.1 处理异常
UpdateException需要配置在统一的异常处理方法中。
3.2 设计请求
- /users/changPassword
- POST
- String oldPassword,String newPassword
- JsonResult<void>
复制代码 3.3 处理请求
- @RequestMapping("/change_password")
- public JsonResult<Void> changePassword(String oldPassword,String newPassword,HttpSession session){
- Integer uid = getUidFromSession(session);
- String username = getUsernameFromSession(session);
- userService.changePassword(uid,username,oldPassword,newPassword);
- return new JsonResult<>(OK);
- }
复制代码 4 修改密码-前端页面
个人资料
1.个人资料-持久层
1.1 需要规划的SQL语句
1.更新用户信息的SQL语句- update t_user set phone=?,email=?,gender=?,modified_user=?,modified_time=? where uid=?
复制代码 2.根据用户名来查询用户的数据- select * from t_user where uid=?
复制代码 1.2 接口与抽象方法
更新用户的信息方法的定义。- /**
- * 更新用户的数据信息
- * @param user 用户的数据
- * @return 返回值为受影响的行数
- */
- Integer updateInfoByUid(User user);
复制代码 1.3 抽象方法的映射
UserMapper.xml文件- <update id="updateInfoByUid">
- UPDATE t_user
- SET <if test="phone!=null">phone=#{phone},</if>
- <if test="email!=null">email=#{email},</if>
- <if test="gender!=null">gender=#{gender},</if>
- modified_user=#{modifiedUser},
- modified_time=#{modifiedTime}
- WHERE uid=#{uid}
- </update>
复制代码 1.4 测试
- @Test
- public void updateInfoByUid(){
- User user=new User();
- user.setUid(11);
- user.setPhone("1232");
- user.setEmail("98670@qq.com");
- user.setGender(1);
- Integer integer = userMapper.updateInfoByUid(user);
- System.out.println(integer);
- }
复制代码 2.个人资料-业务层
2.1 异常规划
- 设计两个功能:
- 当打开页面时,获取用户的信息并填充到对应的文本框中。
- 检测用户是否点击了修改按钮,如果检测到则执行修改用户信息的操作。
- 打开页面的时候可能找不到用户数据,点击删除按钮之前需要再次的去检测用户的数据是否存在
2.2 接口和抽象方法
主要有两个功能的模块,对应的是两个抽象的方法的设计。- /**
- * 根据用户的uid查询用户数据
- * @param uid
- * @return 用户的数据
- */
- User getByUid(Integer uid);
- /**
- * 修改用户信息
- * @param session
- * @param user
- */
- void changeInfo(Session session,User user);
复制代码 2.3 实现抽象方法
在UserServiceImpl类中添加两个抽象方法的具体实现。- @Override
- public User getByUid(Integer uid) {
- User result = userMapper.findByUid(uid);
- if (result==null||result.getIsDelete()==1){
- throw new UsernameNotFoundException("用户数据不存在");
- }else {
- User user=new User();
- user.setEmail(result.getEmail());
- user.setPhone(result.getPhone());
- user.setGender(result.getGender());
- return user;
- }
- }
- @Override
- public void changeInfo(Integer uid,String username, User user) {
- User result = userMapper.findByUid(uid);
- if (result==null||result.getIsDelete()==1){
- throw new UsernameNotFoundException("用户数据不存在");
- }else {
- user.setUid(uid);
- user.setModifiedUser(username);
- user.setModifiedTime(new Date());
- Integer integer = userMapper.updateInfoByUid(user);
- if (integer!=1){
- throw new UpdateException("更新数据时产生未知异常");
- }
- }
- }
复制代码 2.4 接口测试
- @Test
- public void getByUid(){
- System.out.println(userService.getByUid(11));
- }
- @Test
- public void changeInfo(){
- User user = new User();
- user.setPhone("1234");
- user.setEmail("56565@qq.com");
- user.setGender(0);
- userService.changeInfo(11,"denlu",user);
- }
复制代码 3.个人资料-控制层
3.1 处理异常
3.2 设计请求
1.设置-打开页面就发送当前用户的查询。- /users/get_by_uid
- GET
- HttpSession session
- JsonResult<User>
复制代码 2.点击修改按钮发送用户的数据修改操作请求的设计。- /users/change_info
- POST
- User user,HttpSession session
- JsonResult<Void>
复制代码 3.3 处理请求
4. 个人资料-前端页面
1.在打开userdata.html页面自动发送ajax请求,查询到的数据填充到这个页面。
2.在检测到用户点击了修改按钮之后发送了一个ajax请求(change_info)。
上传头像
1.上传头像-持久层
1.1 SQL语句的规划
将对象文件保存在操作系统上,然后再把这个文件路径给记录下来,因为在记录路径的时候是非常的便捷和方便的。将来如果要打开这个文件,可以根据路径去找到这个文件。所以数据库里只要保存文件存储路径即可。将保存的静态资源(图片,文件,其他资源文件)放在某台电脑上,再把这台电脑作为一台单独的服务器使用。
对应是一个用户avatar的sql语句- update t_user set avatar=?,modified_user=?,modified_time=? where uid=?
复制代码 1.2 设计接口和抽象方法
UserMapper接口中来定义这个给抽象方法用于修改用户头像
1.3 接口的映射
UserMapper.xml文件中编写映射的SQL语句。
2.上传头像-业务层
2.1 规划异常
1.用户数据不存在,找不到对应的用户的数据。
2.更新的时候,各种未知的异常产生。
2.2 设计接口和抽象方法
- /**
- * 根据uid修改头像
- * @param uid 用户的id
- * @param avatar 用户的头像路径
- * @param username 用户名
- */
- void changeAvatar(Integer uid,String avatar,String username);
复制代码 2.3 实现抽象方法
- @Override
- public void changeAvatar(Integer uid, String avatar, String username) {
- User user = userMapper.findByUid(uid);
- if(user==null||user.getIsDelete().equals(1)){
- throw new UsernameNotFoundException("用户数据不存在");
- }
- Integer integer = userMapper.updateAvatarByUid(uid, avatar, username, new Date());
- if(integer!=1){
- throw new UpdateException("更新用户头像产生未知的异常");
- }
- }
复制代码 2.4 测试
3.上传头像-控制层
3.1 规划异常
- 父类:FileUploadException 泛指文件上传的异常
- FileEmptyException 文件为空的异常
- FileSizeException 文件大小超出限制
- FileTypeException 文件类型异常
- FileUploadIOException 文件读写的异常
- FileStateException 文件状态异常
复制代码 五个构造方法显式声明出来,再去继承相关的父类
3.2 异常处理
在基类BaseController类中进行编写和统一处理。- if (e instanceof FileEmptyException){
- result.setState(6000);
- result.setMessage("文件空异常");
- }else if (e instanceof FileSizeException){
- result.setState(6001);
- result.setMessage("文件大小异常");
- }else if (e instanceof FileTypeException){
- result.setState(6002);
- result.setMessage("文件类型异常");
- }else if (e instanceof FileStateException){
- result.setState(6003);
- result.setMessage("文件状态异常");
- }else if (e instanceof FileUploadException){
- result.setState(6004);
- result.setMessage("文件上传异常");
- }
复制代码 3.3 设计请求
- /users/change_avatar
- POST(GET请求提交数据2KB)
- HttpSession session,MutipartFile file
- JsonResult<String>
复制代码 3.4 实现请求
- /**
- * MultipartFile接口是SpringMVC提供的一个接口,这个接口为我们包装了获取文件类型的数据(任何类型的file都可以接收),SpringBoot整合了SpringMVC,只需要在处理请求的方法参数列表上声明一个参数类型的MutipartFile的参数,然后SpringBoot自动将传递给服务的文件数据赋值给这个参数
- * @param session
- * @param file
- * @return
- */
- @RequestMapping("change_avatar")
- public JsonResult<String> changeAvatar(HttpSession session, @RequestParam("file") MultipartFile file) {
- if (file.isEmpty()){
- throw new FileEmptyException("文件为空");
- }
- if (file.getSize()>AVATAR_MAX_SIZE){
- throw new FileSizeException("文件超出限制");
- }
- if (!AVATAR_TYPE.contains(file.getContentType())){
- throw new FileTypeException("文件类型不支持");
- }
- String parent=session.getServletContext().getRealPath("upload");
- File dir = new File(parent);
- if (!dir.exists()){
- dir.mkdirs();//创建当前的目录
- }
- String originalFilename = file.getOriginalFilename();
- int index = originalFilename.lastIndexOf(".");
- String suffix=originalFilename.substring(index);//获取后缀(.XXX)
- String filename = UUID.randomUUID().toString().toUpperCase()+suffix;//拼接随机生成的文件名和前面获取到的字符串
- File dest = new File(dir, filename);//在存储路径下写入同名空文件,传回空文件
- try {
- file.transferTo(dest);//头像文件写入空文件中
- } catch (FileStateException e) {
- throw new FileStateException("文件状态异常");
- } catch (IOException e) {
- throw new FileUploadIOException("文件读写异常");
- }
- Integer uidFromSession = getUidFromSession(session);
- String usernameFromSession = getUsernameFromSession(session);
- String avatar="/upload/"+filename;
- userService.changeAvatar(uidFromSession,avatar,usernameFromSession);
- return new JsonResult<>(OK,avatar);
- }
复制代码 4.上传头像-前端页面
在upload页面中编写上传头像代码
说明:如果直接使用表单进行文件的上传,需要给表单显示的添加一个属性enctype="multipart/form-data"声明出来,不会将目标文件的数据结构做修改再上传,不同于字符串
5.解决Bug
5.1 更改默认大小的限制
SpringMVC默认为1MB文件可以进行上传,需要手动修改SpringMVC默认上传文件的大小。
方式1:直接在配置文件中进行配置- spring.servlet.multipart.max-file-size=10MB
复制代码 方式2:采用Java代码的形式来设置文件的上传大小的限制。主类中进行配置,可以定义一个方法,必须使用@Bean修,返回值为MutipartConfigElement。在类的前面添加一个@Configuration进行修饰- @Bean
- MultipartConfigElement getMultipartConfigElement(){
- MultipartConfigFactory multipartConfigFactory = new MultipartConfigFactory();
- multipartConfigFactory.setMaxFileSize(DataSize.of(10, DataUnit.MEGABYTES));
- return multipartConfigFactory.createMultipartConfig();
- }
复制代码 5.2 显示头像
在页面中通过ajax请求来t提交文件,提交完成后,后端返回json串,从中解析出data中的数据,设置到img头像标签的src属性上- serialize()//将表单数据自动拼接成key=value的结构进行提交给服务器,一般提交是普通的控件类型中的数据(text\password\radio\checkbox)等等
- FormdData类//将表单中数据保持原有结构进行数据的提交
- --- new FormData($("#form")[0]);
- ajax默认处理数据时按照字符串的形式进行处理,以及默认会采用字符串的形式进行提交数据。所以要关闭这两个默认的功能。
- --- processData:false,
- --- contentType:false,
复制代码 5.3 登录后显示头像
更新头像成功后,将服务器返回的头像路径保存在客户端cookies对象中,然后每次检查用户打开上传头像页面,这个页面中通过ready()方法来自动检测去读取cookie中头像并设到src属性上。
1.设置cookie中的值
2.在upload页面中引入cookie.js文件
3.在upload.html页面中通过ready()自动读取cookie中的数据。
新增收货地址
1 新增收货地址-数据表的创建
- CREATE TABLE t_address (
- aid INT AUTO_INCREMENT COMMENT '收货地址id',
- uid INT COMMENT '归属的用户id',
- name VARCHAR(20) COMMENT '收货人姓名',
- province_name VARCHAR(15) COMMENT '省-名称',
- province_code CHAR(6) COMMENT '省-行政代号',
- city_name VARCHAR(15) COMMENT '市-名称',
- city_code CHAR(6) COMMENT '市-行政代号',
- area_name VARCHAR(15) COMMENT '区-名称',
- area_code CHAR(6) COMMENT '区-行政代号',
- zip CHAR(6) COMMENT '邮政编码',
- address VARCHAR(50) COMMENT '详细地址',
- phone VARCHAR(20) COMMENT '手机',
- tel VARCHAR(20) COMMENT '固话',
- tag VARCHAR(6) COMMENT '标签',
- is_default INT COMMENT '是否默认:0-不默认,1-默认',
- created_user VARCHAR(20) COMMENT '创建人',
- created_time DATETIME COMMENT '创建时间',
- modified_user VARCHAR(20) COMMENT '修改人',
- modified_time DATETIME COMMENT '修改时间',
- PRIMARY KEY (aid)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码 2 新增收货地址-创建实体类
- private Integer aid;
- private Integer uid;
- private String name;
- private String provinceName;
- private String provinceCode;
- private String cityName;
- private String cityCode;
- private String areaName;
- private String areaCode;
- private String zip;
- private String address;
- private String phone;
- private String tel;
- private String tag;
- private Integer isDefault;
复制代码 3 新增收货地址-持久层
3.1 各功能的开发顺序
当前收货地址功能模块:列表的展示,修改,删除,设置默认,新增收货地址。
开发顺序:新增-展示-设置默认-删除-修改
3.2 规划需要执行的SQL语句
1.新增-对应的是插入语句- insert into t_address(除了aid外字段列表) values(字段值列表)
复制代码 2.一个用户的收货地址最多只能有20条数据对应。在插入用户数据前,先做查询操作。收货地址逻辑控制方面的一个异常。- select count(*) t_address where uid=?
复制代码 3.3 接口和抽象方法
1.创建一个新的接口Address,在这个接口中来定义上面两个SQL语句抽象方法的定义。- /**
- * 插入用户的收货地址数据
- * @param address 收货地址数据
- * @return 受影响的行数
- */
- Integer insert(Address address);
- /**
- * 根据用户的uid统计用户记录的收货地址数量
- * @param uid 用户的uid
- * @return 当前用户的收货地址总数
- */
- Integer countByUid(Integer uid);
复制代码 3.4 配置SQL映射
resource下的AddressMapper.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.cy.store.mapper.AddressMapper">
- <resultMap id="AddressEntityMap" type="com.cy.store.entity.Address">
- <id column="aid" property="aid"/>
- <result column="province_code" property="provinceCode"/>
- <result column="province_name" property="provinceName"/>
- <result column="city_code" property="cityCode"/>
- <result column="city_name" property="cityName"/>
- <result column="area_code" property="areaCode"/>
- <result column="area_name" property="areaName"/>
- <result column="is_default" property="isDefault"/>
- <result column="created_user" property="createdUser"></result>
- <result column="created_time" property="createdTime"></result>
- <result column="modified_user" property="modifiedUser"></result>
- <result column="modified_time" property="modifiedTime"></result>
- </resultMap>
- <insert id="insert" useGeneratedKeys="true" keyProperty="aid">
- INSERT INTO t_address(uid, name, province_name, province_code, city_name, city_code,area_name, area_code, zip, address, phone, tel, tag, isDefault,created_user, created_time, modified_user, modified_time)
- VALUES (#{uid},#{name},#{provinceName},#{provinceCode},#{cityName},#{cityCode},#{areaName},#{areaCode},#{zip},#{address},#{phone},#{tel},#{tag},#{isDefault},#{createdUser},#{createdTime},#{modifiedUser},#{modifiedTime})
- </insert>
- <select id="countByUid" resultType="java.lang.Integer">
- SELECT count(*) from t_address WHERE uid=#{uid}
- </select>
- </mapper>
复制代码 2.在test下的mapper文件夹下创建AddressMapperTests的测试类
4 新增收货地址-业务层
4.1 规划异常
如果用户是第一插入用户的收货地址,规则:当用户插入的地址是第一条,需要将当前地址作为默认收货地址,如果查询到统计总数为0,则将当前地址的is_default值设置为1。查询统计的结果为0不代表异常。查询结果大于20,这时需要抛出业务控制的异常AddressCountLimitException异常。自行创建这个异常。
4.2 接口和抽象方法
1.创建一个IAddressService接口,在接口中定义业务的抽象方法
4.3 实现抽象方法
5 新增收货地址-控制层
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |