创建用户的实体类

  1. 通过表的结构提取出表的公共字段,放在一个实体类的基类中,起名为BaseEntity基类中。
  2. 创建用户的实体类,继承BaseEntity基类

    一、注册功能

    注册-持久层

    通过Mybatis来操作数据库。在做mybatis开发的流程

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

  3. 用户的注册功能:数据的插入操作。

    1. insert into t_user (username, password) values (值列表);
  4. 在用户的注册时,查询用户名是否已经被注册

    1. select * from t_user where username = ?;

    2.设计接口和方法

  5. 定义mapper接口。在项目的目录结构下创建mapper包,来存储UserMapper接口。

  6. 在启动类使用MapperScan注解确定项目中的mapper接口路径。

    3.编写映射

  7. 定义xml映射文件,与对应的接口进行关联。所有的映射文件需要放置在resource目录下,在这个目录下创建mapper文件夹,在mapper文件夹下存放xml文件(mapper的映射文件)

  8. 创建接口对应的映射文件,遵循和接口的名称保持一致即可。
  9. 配置接口中的方法对应上sql语句。需要借助标签来完成。(insert、update、delete、select)
  10. 将mapper文件的位置注册到properties对应的配置文件中

    1. mybatis.mapper-locations=classpath:mapper/**Mapper.xml
  11. 单元测试

    注册-业务层

    1.规划异常

  12. RuntimeException异常作为父类,业务层异常定义为ServiceException

    根据业务层的不同功能来详细定义具体的异常的类型,统一的去继承ServiceException异常类

  13. 用户进行注册时,可能会产生用户名被占用的错误,抛出异常:UsernameDuplicatedException异常(用户名被占用)

  14. 未知的异常,执行数据插入操作,服务器宕机、数据库宕机。处于正在执行插入的过程中所产生的异常InsertException。

    2.设计接口和抽象方法

  15. 在srevice包下创建IUserService接口

  16. 创建一个实现类UserServiceImpl类,需要实现这个接口,并且实现抽象方法。
  17. 单元测试包下创建UseServiceTests类,在这个类当中进行单元测试

    注册-控制层

    1.创建响应

    状态码、状态信息描述、数据。
    将这三个数据封装在一个类当中,将这个类作为响应的返回值,返回给前端。

    2.设计请求

    依据当前业务功能模块进行请求的设计

    请求路径:/users/reg 请求参数:User user 请求类型:POST 响应结果:JsonResult

3.处理请求

  1. 创建一个控制层对应的类UserController类。依赖于业务层的接口。

    4.控制层优化设计

    在控制层抽离出来一个父类,在这个父类中统一进行异常的相关操作。编写BaseController类

    注册-前端页面

    使用ajax来进行与后端的异步数据通信

    1. <script type="text/javascript">
    2. //1.监听注册按钮是否被点击
    3. $("#btn-reg").click(function () {
    4. // var username = $("#username").val();
    5. // var pwd = $("#password").val();
    6. //发送ajax请求
    7. //serialize自动获取表单内容并且自动拼接起来
    8. $.ajax({
    9. url:"/user/reg",
    10. type:"POST",
    11. data:$("#form-reg").serialize(),
    12. dataType:"JSON",
    13. success:function (json) {
    14. if(json.state == 200){
    15. alert("注册成功!");
    16. location.href = "login.html";
    17. }else{
    18. alert("注册失败!" + json.message);
    19. }
    20. },
    21. error:function (xhr) {
    22. alert("注册时产生未知的错误!" + xhr.status);
    23. }
    24. });
    25. });
    26. </script>

    二、登录功能

    登录-持久层

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

    根据用户提交的用户名和密码进行select查询,密码比较在业务层执行

    1. select * from t_user where username = ?;

    说明:如果在分析过程中发现某个功能模块已经被开发完成,就可以省略开发,但分析过程不可省略

2.接口设计和方法

同上

登录-业务层

1.规划异常

  1. 用户名与密码不匹配:PasswordNotMatchException异常,属于运行时异常,业务层异常
  2. 用户名没有被找到:UsernameNotFoundException异常,属于运行时异常,业务层异常
  3. 异常编写:

    1. 业务层异常需要继承ServiceException异常类
    2. 在具体的异常类中定义构造方法

      2.设计业务层接口和抽象方法

  4. 直接在IUserService接口中编写抽象方法,login(String username,String password);将当前用户登陆成功的用户数据以当前用户对象的形式进行返回。状态管理:将数据保存在cookie或者session中,可以避免重复度很高的数据频繁进行操作数据进行获取(用户名、用户id-存放在session中,用户头像存储在cookie中)

  5. 需要在实现类实现父接口中的抽象方法
  6. 单元测试

    3.抽象方法的实现

登录-控制层

1.处理异常

业务层抛出的异常是什么,需要在统一的异常处理类中进行统一的捕获
image.png

2.设计请求

请求路径:/user/login 请求方式:POST 请求数据:String username,String password,HttpSession session 响应结果:JsonResult

3.处理请求

在UserController类中编写处理请求的方法

登录-前端

  1. //检测按钮点击
  2. $("#btn-login").click(function () {
  3. $.ajax({
  4. url:"/user/login",
  5. type:"POST",
  6. data:$("#form-login").serialize(),
  7. dataType:"JSON",
  8. success:function (json) {
  9. if(json.state == 200){
  10. alert("登陆成功");
  11. //跳转到系统的主页
  12. location.href = "index.html";
  13. }else {
  14. alert("登陆失败");
  15. }
  16. },
  17. error:function (xhr) {
  18. alert("登陆时产生未知异常" + xhr.message);
  19. }
  20. })
  21. });

用户会话Session

session对象主要存储在服务器端,可以用于保存服务器的临时数据的对象,保存的数据可以在整个项目中都可以通过访问来获取,将session的数据看作一个共享的数据,首次登录的时候所获取到的用户数据转移到session对象中。session。getAttrbute(”key”),可以将获取session中的数据这种行为进行封装,封装在BasesController

  1. 封装session的获取和设置,用户登录成功后进行数据设置
  2. 在父类中封装两个数据,uid和username,用户头像则放在cookie中
  3. 在登陆方法中将数据封装在Session中

    拦截器

    将所有的请求统一拦截到拦截器中,可以在拦截器中来定义过滤的规则,如果不满足系统设置的过滤规则,统一处理是重新去打开login.html(重定向和转发),推荐使用重定向。
    在SpringBoot项目中拦截器的定义和使用。SpringBoot是依靠SpringBootMVC来完成的。SpringMVC提供了一个HandlerInerceptor接口,用于表示定义一个拦截器。首先自定义一个类,在让这个类实现这个接口。

  4. 自定义一个类,实现HandlerInerceptor接口

  5. 注册过滤器:添加白名单(login.html、register.html等)、添加黑名单。
  6. 注册过滤器的技术:WebMvcConfigure接口,可以将用户定义的了拦截器进行注册,才可以保证拦截器能够生效和使用。配置信息存放在config包结构下

    三、修改密码功能

    需要用户提交原始密码和新密码,再根据当前登陆的用户进行信息修改的操作

    修改密码-持久层

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

    根据用户的uid修改用户password值

    1. update t_user set password = ? ,modified_user = ?, modified_time = ? where uid = ?;

    根据uid查询用户的数据。在修改密码之前,要保证当前用户是否存在,是否标记为已删除,检测原密码是否相同

    1. select * from t_user where uid = ?;

    2.设计接口和抽象方法

    使用UserMapper接口

    3.SQL的映射

    4.单元测试

    修改密码-业务层

    1.规划异常

  7. 用户愿密码错误,isdelete == 1,uid找不到

  8. 更新时出现未知的异常,updateException

    2.设计接口和抽象方法

    执行修改密码的操作
    在实现中实现方法
    单元测试

    修改密码-控制层

    1.异常处理

    UpdateException需要配置在统一的异常处理方法中。BaseController中

    2.设计请求

    /user/change_password post String oldPassword, String newPssword,HttpSession session JsonResult

3.处理请求

controller中处理

  1. @RequestMapping("change_password")
  2. public JsonResult<Void> changPassword(String oldPassword, String newPassword,HttpSession session){
  3. Integer uid = getUidFromSession(session);
  4. String username = getUsernameFromSession(session);
  5. userService.changePassword(uid,username,oldPassword,newPassword);
  6. return new JsonResult<>(OK);
  7. }

修改密码-前端

  1. <script type="text/javascript">
  2. //检测按钮点击
  3. $("#btn-change-password").click(function () {
  4. $.ajax({
  5. url:"/user/change_password",
  6. type:"POST",
  7. data:$("#form-change-password").serialize(),
  8. dataType:"JSON",
  9. success:function (json) {
  10. if(json.state == 200){
  11. alert("密码修改成功");
  12. //跳转到系统的主页
  13. location.href = "index.html";
  14. }else {
  15. alert("密码修改失败");
  16. }
  17. },
  18. error:function (xhr) {
  19. alert("修改密码时产生未知异常" + xhr.message);
  20. }
  21. })
  22. });
  23. </script>

四、个人资料的修改

资料修改-持久层

1.设计SQL语句

  1. 更新用户信息的SQL语句

    1. update t_user set phone = ? ,email = ?, gender = ?, modified_user = ?, modified_time = ? where uid = ?;
  2. 根据uid来查询用户的数据

    1. select * from t_user where uid = ?;

    2.接口与抽象方法

    更新用户的信息方法

    3.方法的映射

    在UserMapper.xml映射

    4.单元测试

    资料修改-业务层

    1.规划异常

  3. 设计两个功能:

  • 打开页面获取当前用户的信息,并将其设置到文本框中
  • 当用户点击修改按钮后进行相关信息的更新操作
  1. 打开页面后发现找不到用户数据了;点击更新时要再次进行用户信息的查询,看用户信息是否仍旧存在。

    2.设计接口和抽象方法

    主要有两个功能,对应两个抽象方法中

    3.实现抽象方法

    4.单元测试

    资料修改-控制层

    1.处理异常

    暂无

    2.设计请求

  2. 设置一打开页面就进行数据查询

    /user/get_by_uid get HttpSession session JsonResult

  3. 点击修改按钮,发送用户的数据修改操作请求

    /user/change_info POST HttpSession session, User user JsonResult

3.处理请求

4.测试

资料修改-前端

访问userdate.html页面直接查询并复制
点击修改按钮后,发送求情

五、头像上传功能

上传头像-持久层

1.设计SQL

将对应的文件保存在操作系统上,然后记录这个文件的路径。

  1. update t_user set avatar = ?, modified_user = ?, modified_time = ? where uid = ?

2.设计接口和抽象方法

在UserMapper中去写

3.接口的映射

UserMapper.xml

4.单元测试

上传头像-业务层

1.规划异常

  1. 用户数据不存在,找不到对应的用户
  2. 更新时,未知的错误

    2.设计接口和抽象方法

    3.实现方法

    4.测试

    上传头像-控制层

    1.规划异常

    1. FileUploadException泛指文件上传异常(父类)继承RuntimeException
    2. FileEmptyException文件为空的异常
    3. FileSizeException文件大小超出限制异常
    4. FileTypeException文件类型异常
    5. FileIUploadIOException文件读写异常
    6. FileStateException文件状态异常(已被打开等状态)

    2.处理异常

    在BaseConyroller中处理
    1. else if (e instanceof FileEmptyException) {
    2. result.setState(6000);
    3. } else if (e instanceof FileSizeException) {
    4. result.setState(6001);
    5. } else if (e instanceof FileTypeException) {
    6. result.setState(6002);
    7. } else if (e instanceof FileStateException) {
    8. result.setState(6003);
    9. } else if (e instanceof FileUploadIOException) {
    10. result.setState(6004);
    11. }
    在统一的异常处理方法的参数列表上增加新的异常处理作为他的参数
    image.png

    3.设计请求

    /user/change_avatar POST(get请求提交数据大约2kb) HttpSession session,MutipartFile file JsonResult

4.实现请求

上传头像-前端页面

在upload.html页面编写,from表单中添加如下属性

  1. <form action="/user/change_avatar"
  2. method="post"
  3. enctype="multipart/form-data"
  4. class="form-horizontal"
  5. role="form">

解决BUG

1.更改默认的大小限制

SpringMVC默认为1MB的文件可以进行上传,手动去修改
方式一:配置文件中修改

  1. spring.servlet.multipart.max-file-size=10MB
  2. spring.servlet.multipart.max-request-size=15MB

方式二:需要采用java代码的形式来设置文件的上传限制。主类中进行配置,定义一个方法,必须使用@Bean来修饰。在主类的前面添加@Configration注解进行修改。方法的返回值必须是MultipartConfigElement类型

  1. @Bean
  2. public MultipartConfigElement getMultipartConfigElement(){
  3. //创建一个配置的工厂类对象
  4. MultipartConfigFactory factory = new MultipartConfigFactory();
  5. //设置需要创建的对象的相关信息
  6. factory.setMaxFileSize(DataSize.of(10, DataUnit.MEGABYTES));
  7. factory.setMaxRequestSize(DataSize.of(15,DataUnit.MEGABYTES));
  8. //通过工厂类来创建MultipartConfig对象
  9. return factory.createMultipartConfig();
  10. }

3.显示头像

在页面中通过ajax请求来提交文件,并从json中提取出来图片信息,设置到img标签的src属性上

  • serialize():可以将表单中的数据自动拼接成key=value的结构提交给服务器,一般提交普通的控件类型中的数据(text、password、radio、checkbox)等等
  • FormData类:表示表单当中的数据保持原有的结构进行数据的提交。

    1. new FormData($("#form")[0]);//文件类型的数据可以使用FormData对象进行存储
  • ajax默认处理数据时按照字符串的形式进行处理,以及默认会采用字符串的形式进行数据提交,关闭这两个默认的功能

    1. processData: false,//处理数据的形式,关闭处理数据
    2. contentType:false,//提交数据的形式,关闭默认提交数据的形式

    4.登陆后显示头像

    在更新头像成功后,将服务器返回的头像路径保存在客户端的Cookie中,然后检测页面打开,在这个页面中通过rendy方法来自动检测去去读取cookie中头像的地址并设置到src中

  1. 设置cookie的值,先导入js文件

    1. <script src="../bootstrap3/js/jquery.cookie.js" type="text/javascript" charset="utf-8"></script>
    2. $.cookie(key,value,time);单位为天
  2. 通过redy自动读取

    5.显示最新头像

    再更改完头像后,将新的头像中值,再次保存在cookie中

    1. $.cookie("avatar",json.data.avatar,{expires: 7});