java踩坑日记

1:环境:idea 14版本,win10,springboot

2:第一个问题:必须使用shiro实现登录(加验证码)

参考资料: https://blog.csdn.net/qq_34021712/article/details/80470738     ©王赛超 

验证码校验:

@RequestMapping(value = "/login",method = RequestMethod.POST)
public String loginUser(HttpServletRequest request, String username, String password,boolean rememberMe,String captcha, Model model) {

//校验验证码
//session中的验证码
String sessionCaptcha = (String) SecurityUtils.getSubject().getSession().getAttribute(CaptchaController.KEY_CAPTCHA);
if (null == captcha || !captcha.equalsIgnoreCase(sessionCaptcha)) {
model.addAttribute("msg","验证码错误!");
return "login";
}
//对密码进行加密
//password=new SimpleHash("md5", password, ByteSource.Util.bytes(username.toLowerCase() + "shiro"),2).toHex();
//如果有点击 记住我
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password,rememberMe);
//UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
try {
//登录操作
subject.login(usernamePasswordToken);
return "redirect:index";
} catch(Exception e) {
//登录失败从request中获取shiro处理的异常信息 shiroLoginFailure:就是shiro异常类的全类名
String exception = (String) request.getAttribute("shiroLoginFailure");

if(e instanceof UnknownAccountException){
model.addAttribute("msg","用户名或密码错误!");
}
if(e instanceof IncorrectCredentialsException){
model.addAttribute("msg","用户名或密码错误!");
}
if(e instanceof LockedAccountException){
model.addAttribute("msg","账号已被锁定,请联系管理员!");
}
//返回登录页面
return "login";
}
}

  此处我将此模块放在logincontroller里面专门处理登录操作;下面的为验证码的生成;新建一个CaptchaUtil将它放在utils下面,标黄的地方注意是你自己定义的路径

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Random;

import javax.imageio.ImageIO;

/**
 * 验证码工具类
 */
public class CaptchaUtil {

    // 随机产生的字符串
    private static final String RANDOM_STRS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final String FONT_NAME = "Fixedsys";
    private static final int FONT_SIZE = 18;

    private Random random = new Random();

    private int width = 80;// 图片宽
    private int height = 25;// 图片高
    private int lineNum = 50;// 干扰线数量
    private int strNum = 4;// 随机产生字符数量

    /**
     * 生成随机图片
     */
    public BufferedImage genRandomCodeImage(StringBuffer randomCode) {
        // BufferedImage类是具有缓冲区的Image类
        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_BGR);
        // 获取Graphics对象,便于对图像进行各种绘制操作
        Graphics g = image.getGraphics();
        // 设置背景色
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height);

        // 设置干扰线的颜色
        g.setColor(getRandColor(110, 120));

        // 绘制干扰线
        for (int i = 0; i <= lineNum; i++) {
            drowLine(g);
        }
        // 绘制随机字符
        g.setFont(new Font(FONT_NAME, Font.ROMAN_BASELINE, FONT_SIZE));
        for (int i = 1; i <= strNum; i++) {
            randomCode.append(drowString(g, i));
        }
        g.dispose();
        return image;
    }

    /**
     * 给定范围获得随机颜色
     */
    private Color getRandColor(int fc, int bc) {
        if (fc > 255){
            fc = 255;
        }
        if (bc > 255){
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

    /**
     * 绘制字符串
     */
    private String drowString(Graphics g, int i) {
        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
                .nextInt(121)));
        String rand = String.valueOf(getRandomString(random.nextInt(RANDOM_STRS
                .length())));
        g.translate(random.nextInt(3), random.nextInt(3));
        g.drawString(rand, 13 * i, 16);
        return rand;
    }

    /**
     * 绘制干扰线
     */
    private void drowLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int x0 = random.nextInt(16);
        int y0 = random.nextInt(16);
        g.drawLine(x, y, x + x0, y + y0);
    }

    /**
     * 获取随机的字符
     */
    private String getRandomString(int num) {
        return String.valueOf(RANDOM_STRS.charAt(num));
    }

    public static void main(String[] args) {
        CaptchaUtil tool = new CaptchaUtil();
        StringBuffer code = new StringBuffer();
        BufferedImage image = tool.genRandomCodeImage(code);
        System.out.println("random code = " + code);
        try {
            // 将内存中的图片通过流动形式输出到客户端
            ImageIO.write(image, "JPEG", new FileOutputStream(new File(
                    "/Users/wangsaichao/Desktop/random-code.jpg")));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

  登录界面的代码,如果是这样的话你会发现页面根本不会出现验证码,标黄部分是验证码刷新代码,你必须调用此方法来进行验证码的生成,标红部分为你的logincontroller里面的方法路径。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8" />
    <title>Insert title here</title>
</head>
<body>
<h1>欢迎登录</h1>
<h1 th:if="${msg != null }" th:text="${msg}" style="color: red"></h1>
<form action="/login" method="post">
    用户名:<input type="text" name="username"/><br/>
    密码:<input type="password" name="password"/><br/>
    验证码:<input type="text" name="captcha"/><img alt="验证码" th:src="@{/Captcha.jpg}" title="点击更换" id="captcha_img"/>
    (看不清<a href="javascript:void(0)" onclick="javascript:refreshCaptcha()">换一张</a>)<br/>
    <input type="checkbox" name="rememberMe" />记住我<br/>
    <input type="submit" value="提交"/> <button><a href="/unlockAccount">解锁admin用户</a></button>
</form>
</body>

<script type="text/javascript">
    window.οnlοad=kickout();
    

加上:
$(function(){
refreshCaptcha();
})
    function refreshCaptcha(){
        $("#captcha_img").attr("src","/Captcha.jpg?id=" + new Date() + Math.floor(Math.random()*24));
    }
</script>
</html>

  然后说说我遇到的问题:账号密码输入正确但是登陆不了,原因就是shiro默认会将你的密码进行md5加密,匹配的时候要么将shiro的md5加密去掉,要么就是将密码进行md5加密后再进行匹配。shiro是不需要你进行数据库查找的,他默认的进行了这一操作。

3.第二个问题,普遍的跳转

  方式有多种,这里只说的是controller里面的跳转:

@RequestMapping("/")
    public String index() {
        return "login";
    }

@RequestMapping("/")
    public String index() {
        return "redirect:/login";
    }

  上述的两种跳转是比较多的,第一种,直接return,那么它是找的你的.jsp文件。第二种,redirect:/login解释为重定向,他会在controller里面找到相应的以RequestMapping("/login")为开头的方法。然后进行跳转。

另外的涉及到页面的相互传值的问题(跳转),以一个案例来分析

logincontroller里面
@RequestMapping("/edit") public String userEdit(Model model, HttpServletRequest request) { String id = request.getParameter("id"); int userid = Integer.parseInt(id); 方法 model.addAttribute("user", uservo);传值方式 return "页面"; } @RequestMapping("/editUser") @ResponseBody public ResultVo edit(UserEntity userEntity) { ResultVo result = new ResultVo(); 方法 if (CommonUtil.isNotNull(userVo)) { result.setSuccess(false); } else { result.setSuccess(true); } return result; } 页面主要的ajax传值代码 $.ajax({ type: "POST", async: "false", dataType1: "json", data : t, url: "${root}/user/editUser", //传入值 success: function (data) { if(data.success){ window.location.href ='${root}/edit'; //跳转界面 } } });

  流程为:主页面加载完成:点击编辑按钮,在editUser里面进行判断,返回的result为true和false,如果返回为true则会跳转到edit,edit跳转到相应的页面。

猜你喜欢

转载自www.cnblogs.com/FlowerNotGiveYou/p/11511154.html