码迷,mamicode.com
首页 > 编程语言 > 详细

java初探(1)之登录再探

时间:2020-02-17 20:14:34      阅读:112      评论:0      收藏:0      [点我收藏+]

标签:getc   instance   网络   安全   exce   接口   smo   error   type   

https://www.cnblogs.com/lovejune/p/java_login_1.html

上一章内容搭建起了登录应用场景的环境,模拟实现了登录操作,页面与后端数据的交互过程,使用的是异步的ajax请求实现。

在LoginController中,我们实现了对数据的简单校验,但事实上,在实际开发中,我们不可能使用这么繁琐的校验代码。校验过程,交给javax.validation.Valid类来实现。

下面将研究javax.validation.Valid的原理和使用方法。

  • @Valid注解

  用于校验的注解,所属包为javax.validation.Valid,

在LoginController类中修改如下代码

@RequestMapping("/do_login")
    @ResponseBody
    public Result<Boolean> dologin(HttpServletResponse response, @Valid Person person, BindingResult bindingResult){

        System.out.println(person);
        if(bindingResult.hasErrors()){
            System.out.println(bindingResult.getFieldError().getDefaultMessage());
            return null;
        }

        Result<Boolean> result = userService.login(person);


        return result;
    }

BindingResult类是跟在@Valid后面的结果类,若校验出错,该对象会返回出错信息。但这样的代码仍然比较繁琐,且无法与我们自定义的结果类相关联。

在参数中去掉BindingResult bindingResult,运行程序,发现执行ajax的error里面的代码,所以请求出错了,推测这是因为@Valid验证不通过会在内部报错,如果没有BindingResult ,将报错,此刻,需要引入spring中的异常管理。

接下来,使用@ControllerAdvice注解来统一处理异常,该注解是@Controller注解的增强,当将异常抛到controller时,可以对异常进行统一处理,规定返回的json格式或是跳转到一个错误页面。

 

  • 自定义异常类

定义一个全局异常类,将所有的异常都交给controller来处理

public class GobalException extends RuntimeException {

    private Integer code;
    private String Msg;

    @Override
    public String toString() {
        return "GobalException{" +
                "code=" + code +
                ", Msg=‘" + Msg + ‘\‘‘ +
                ‘}‘;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return Msg;
    }

    public void setMsg(String msg) {
        Msg = msg;
    }
}

 

  • 修改自定义的结果类

package com.liuxinghang.result;

public class Result {

    private Integer code;
    private String Msg;

    //定义构造方法

    public Result(Integer code,String Msg){
        this.code=code;
        this.Msg=Msg;
    }

    public Result(){

    }

    //定义静态属性拿值
    public static Result NOPERSON=new Result(0,"查无此人");

    public static Result ERRORPASS=new Result(01,"密码错误");

    public static Result SUCCESS=new Result(1,"登录成功");

    public static Result SEVERERROR=new Result(000,"服务器异常");

    public static Result error(Integer code,String Msg){
        return new Result(code,Msg);
    }


    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", Msg=‘" + Msg + ‘\‘‘ +
                ‘}‘;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return Msg;
    }

    public void setMsg(String msg) {
        Msg = msg;
    }

}

该结果类虽然修改了,但仍然有很多瑕疵,可以进一步抽象。

  • 异常处理类

@ControllerAdvice
@ResponseBody //出现异常,将异常信息通过response返回
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    public Result exceptionHandle(HttpServletResponse response,Exception e){
        e.printStackTrace();

        //判断异常类型
        if(e instanceof GobalException){
            System.out.println("GobalException异常");
            return new Result(((GobalException) e).getCode(),((GobalException) e).getMsg());
        }else if(e instanceof BindException){
            System.out.println("BindException异常");
            BindException ex = (BindException)e;
            List<ObjectError> errors = ex.getAllErrors();
            ObjectError error = errors.get(0);
            String msg = error.getDefaultMessage();
            return new Result(123,msg);
        }else {
            return Result.SEVERERROR;
        }
    }
}

 

总结来说,异常处理类,通过注解@ControllerAdvice和@ResponseBody 以及@ExceptionHandler(value = Exception.class)使得所有的异常统一进行处理,并通过response来返回异常消息,也可以通过渲染页面,返回到错误的页面中。

到此,我们已经了解了登录时对消息验证的交互逻辑,接下来,探索如何自定义验证规则,来完成我们自己数据的验证,用户通过手机号来进行登录,可以验证手机号码是否符合规则,比如,手机号为11位,而且第一个数字一定为1。

 

  • ValidatorUtil类,定义isMobile方法

 此类通过一个pattern类对传来的数据进行正则约束,返回一个布尔类型

public class ValidatorUtil {

    private static Pattern MOBILE_PATTERN = Pattern.compile("1\\d{10}");

    public static boolean isMobile(String mobile){
        if(StringUtils.isEmpty(mobile)){
            return false;
        }
        Matcher matcher=MOBILE_PATTERN.matcher(mobile);
        return matcher.matches();
    }
}

 

该类通过对手机号码的格式提出一定要求,符合返回true,不符合返回false

 

  • IsMobile注解的自定义

自定义注解只需创建一个接口,在interface前加个@,java有四个元注解,来规定注解的使用范围,文档等。

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {IsMobileValidator.class }) //处理自定义规则的逻辑


public @interface IsMobile {

    boolean required() default true;
    String message() default "手机号码格式错误";
    //分组
    Class<?> [] groups() default {};
    //负载
    Class<? extends Payload> [] payload() default {};
}

 @Constraint(validatedBy = {IsMobileValidator.class }) //处理自定义规则的逻辑,

IsMobileValidator来自定义的处理格式的逻辑代码,该类必须继承ConstraintValidator接口,来实现方法。该接口有两个参数,一个是校验逻辑的类,一个是待校验的属性的参数。

public class IsMobileValidator implements ConstraintValidator<IsMobile,String> {

    private boolean required=false;

    @Override
    public void initialize(IsMobile isMobile) {
        required=isMobile.required();
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if(required){
            return ValidatorUtil.isMobile(s);
        }else  if(StringUtils.isEmpty(s)){
            return true;
        }else {
            return ValidatorUtil.isMobile(s);
        }
    }
}

 

 

到现在为止,我们自己定义了一个校验的规则IsMobile,判断手机号是不是1开头的十一位数字。

  • 测试

技术图片

 

 可以得到BindException传回的消息与定义的消息一致。

 


接下来,针对网络中密码传播不安全的需求,对密码进行加密。

密码加密对于登录场景有着重要的意义,原则是,明文密码不能在网络上传播,因此,需要在客户端就对密码进行加密,使用md5算法进行加密。该算法的加密过程是固定的,需要加入随机盐来增加不确定性。

  • 修改login.html页面

 function login(){
        var inputPass=$("#password").val();
        var salt = "1a2b3c4d";
        var str = ""+salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);
        var password = md5(str);

        $.ajax({
            url: "/login/do_login",
            type: "POST",
            data:{
                mobile:$("#mobile").val(),
                password: password
            },
            success:function(data){
               alert(data.code+"+"+data.msg+"+"+data.date);
            },
            error:function(){
                alert("错误")
            }
        });
    }

对客户端输入的密码进行加密。

在服务端拿到密码后,再进行加密,二次加密后的密码存到数据库中,以防止进行密码反查而得到确定的密码。

  • Md5Util类

public class Md5Util {
    private static String SALT="1a2b3c4d";

    //md5加密
    private static String md5(String pass){
        return DigestUtils.md5Hex(pass);
    }

    //加密
    public static String dbPass2FormPass(String dbPass){
        String src=""+SALT.charAt(0)+SALT.charAt(2)+dbPass+SALT.charAt(5)+SALT.charAt(4);
        return md5(src);
    }

}

到这里,前端和服务器的交互已经大致完成,剩下的是一些耦合性太高的代码需要重新设计。

下面将开始探究服务器和数据库的交互,包括Mysql数据库和Redis数据库。

 

 

 

 

 

java初探(1)之登录再探

标签:getc   instance   网络   安全   exce   接口   smo   error   type   

原文地址:https://www.cnblogs.com/lovejune/p/12322523.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!