P4用户注册,登录

161 阅读6分钟

spring MVC

  • DisparcherServlet

Java针对web开发制定的标准。解析前端请求的路径背后是哪个controller处理的。

扫描controller并储存。返回HandlerExecutionChain,包含bean和拦截器。

如果adapter返回的是json字符串,可以直接返回给前端。通过@responsebody注解

  1. 用户向服务器发送请求,请求会到DispatcherServlet,DispatcherServlet 对请求URL进行解析,得到请求资源标识符(URI)

  2. 然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括一个Handler处理器对象、多个HandlerInterceptor拦截器对象),最后以HandlerExecutionChain对象的形式返回。

  3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter【适配器,持有对controller的引用,它调用】。提取Request中的模型数据,填充Handler入参开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

  4. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象

  5. 根据返回的ModelAndView,选择一个适合的ViewResolver【视图解析器】返回给DispatcherServlet

  6. ViewResolver 结合Model和View,来渲染视图,最后将渲染结果以view形式封装,返回给客户端。

image.png

处理mv processdispatchresult——如果mv不为空,调render()方法【渲染】——调resolveViewName()方法的viewResolvers找模板引擎,渲染到上面。

mybatis

安装插件,P4,45min左右。只需要在mapper类上加@mapper注解

  • 自动配置,都是以autoconfiguration结尾

程序启动,auto配置类被调用,会主动创建sqlxxxfactory,调用configuration读取配置文件包括【application.properties和扫描mapper.xml】。

sqlxxxfactory就加载好了与配置类有关的内容。

auto再去调用mapperautoconfig,会扫描带有@mapper注解的接口,由mapperproxy动态代理来实现他们。@autowrite注入的mapper,传入的是mapperproxy实现的实现类bean

image.png

sqlxxfactory创建sqlxx,依赖于datasourse 【就是图右下角configuration】

源码流程:

自动配置

datasourceautoconfiguration数据源自动配置【抽象的/spring默认的】

看注解:配置类//有xx时实例化//无xx时实例化//启用(加载)xx配置类//注入xxbean

image.png

datasourceproperties就是就是图右下角configuration配置类(全局配置类)

image.png

注解表示:前缀是spring.datasource。把所有前缀是spring.datasource的加载到datasourceproperties这个bean里

image.png

druid连接池自动配置【具体的】

image.png

方法名跟返回值同名

@bean注解 把方法返回的对象,加载到容器里

@conditiononmissingbean注解 程序里面没有这个方法的实例时,会调用这个方法,创建实例

image.png

mybatis自动配置

image.png

P3.1h26min左右

公共代码

  • businessexception:定义的公共异常,后端所有异常捕获后,包装成这个统一异常抛

  • errocode:定义异常的编号

  • responsemodel:统一生成返回对象,规范json格式。前后端分离都返回json数据。把数据封装成对象,序列化成json。

  • toolbox:工具箱。md5加密方案(spring自带)+盐

image.png

异常统一处理

基于spring mvc实现

后端代码分三层:视图/业务/数据。在哪层抛都会在controller层处理。怎么让三层的异常都在controller统一处理?

  • spring mvc的机制@controlleradvice 控制层通知

    • 建advice类,加上@controlleradvice注解,里面的方法名无所谓,方法参数传入异常父类
    • @exceptionhandler 在异常发生时调用方法
    • @responesebody 返回的是json字符串

image.png

项目可以有多个环境的配置文件/日志的配置文件,可以在此选择激活哪个【哪组】

image.png

日志的配置文件可以有多个,需要配置日志存储路径

image.png

还可配置不同包的,日志打印级别。 要看SQL配置debug级别,debug级别会打印sql

image.png

表示出现404异常由springmvc处理

image.png

模块代码

image.png

entity/user

后台校验注解,属性不能为空。加在定义属性的变量上

@notblank:string不能为null且不能为空字符串

@notnull

前台注册会有校验,不能为空,但是后台也要校验,防止postman的模拟请求击破接口。

image.png

在配置xml文件中,引入校验工具hibernate.validator

image.png

@min,@max注解,最值范围校验,由objectvalidator公用的组件封装

image.png

objectvalidator组件/类

  • 公共组件,受容器管理。
  • 通过validation实例化了validator对象。
  • 提供validate方法,传入参数为object对象。
  • 返回的map,存的key属性名+value消息
  • 底层调用实例化的validator的validate方法,会根据注解,检查传入的object,哪些字段有问题,返回元素为对象的集合。
  • 解析出来哪个属性有问题,问题消息是什么,存到map中

image.png

dao/usermapper

注册登录功能,插件生成的,要加@mapper注解。

增删改查方法,根据手机号查询方法。

image.png

每个方法,需要SQL文件与之对应resources/mappers包下

resources/mappers/usermapper.xml

写dao包下类的sql语句。

parametertype:定义传入参数的类型

resultmap:返回jdbc的结果集

image.png

  • 返回的是结果集,装到user对象里。
  • 数据库字段跟对象属性的映射关系,已经写好。

image.png

  • 编译时#{}会被替换成?号,执行时?号会被替换成form参数
  • jdbctype=varchar表示,数据库字段的varchar类型映射成string类型

image.png

service/UserService

注册方法、登录方法、根据id查询用户

service/impl/UserServiceimpl

@transaction注解,表示方法受事务保护,在一个事务内。有dml语句都加。

  1. 注入userMapper和validator
  2. 注册方法,参数是用户
  3. 先判断是否空,否继续
  4. 校验一下,校验返回结果非空则有问题,抛异常。否继续
  5. 尝试插入(注册)方法,可能手机号重复,就插入失败,则捕获到异常。
  6. 否,插入成功
@Service
public class UserServiceImpl implements UserService, ErrorCode {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ObjectValidator validator;

    @Transactional
    public void register(User user) {
        if (user == null) {
            throw new BusinessException(PARAMETER_ERROR, "参数不能为空!");
        }

        Map<String, String> result = validator.validate(user);
        if (result != null && result.size() > 0) {
            throw new BusinessException(PARAMETER_ERROR,
                    StringUtils.join(result.values().toArray(), ", ") + "!");
        }

        try {
            userMapper.insert(user);
        } catch (DuplicateKeyException e) {
            throw new BusinessException(PARAMETER_ERROR, "该手机号已注册!");
        }
    }

    public User login(String phone, String password) {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(password)) {
            throw new BusinessException(PARAMETER_ERROR, "参数不合法!");
        }

        User user = userMapper.selectByPhone(phone);
        if (user == null || !StringUtils.equals(password, user.getPassword())) {
            throw new BusinessException(USER_LOGIN_FAILURE, "账号或密码错误!");
        }

        return user;
    }

    public User findUserById(int id) {
        return userMapper.selectByPrimaryKey(id);
    }

}

controller/UserController

前端

.html前端表单外观页面,代码文件/.js前端数据,代码文件

  1. 页面加载完成后,给按钮绑定单击事件,调用xx方法
  2. 获取xx,xxx,验证是否为空。为空不通过
  3. 不为空发送ajax异步请求,固定格式

get请求,发送ajax请求,是异步的,通过路径传数据,成功时回调

  1. 跨域

post传址路径上看不到,更安全。post需要传明确的数据,不是通过路径传,要声明数据,json格式

  1. type/url/data/xhrFields
  2. 成功时回调方法,也叫成功时的响应。失败给一个提示,成功页面跳转。

报错是advice统一报的

$(document).ready(function () {
    // 立即登录单击事件
    $("#btn-login").click(function (e) { 
        login(e);
    });
});

function login(e) {
    var phone = $("#phone").val();
    var password = $("#password").val();

    if (!phone) {
        alertBox("手机号不能为空!");
        return false;
    }
    if (!password) {
        alertBox("密码不能为空!");
        return false;
    }

    $.ajax({
        type: "POST",
        url: SERVER_PATH + "/user/login",
        data: {
            "phone": phone,
            "password": password
        },
        xhrFields: {withCredentials: true},
        success: function (result) {
            if (result.status) {
                alertBox(result.data.message);
                return false;
            }
            alertBox("登录成功!", function() {
                window.location.href = "seckill.html";
            });
        }
    });
}

小结:

"#{}"会经过预编译。常用 "${}"直接拼上值,会有注入攻击风险