SSH登陆模块

利用Maven搭建的SSH实现带有验证码和密码加密方式的登陆功能。

搭建SSH

首先搭建SSH,可以参考利用Maven搭建SSM项目

配置实体类

利用注解配置User实体类,然后利用Hibernate生成相应的数据表。注意要在Hibernate配置文件中配置实体类的位置和表的生成策略。


@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long user_id;
    @Column
    private String user_code;
    @Column
    private String user_name;
    @Column
    private String user_password;
    @Column
    private Character user_state;

    public String getUser_code() {
    return user_code;
    }

    public void setUser_code(String user_code) {
    this.user_code = user_code;
    }

    public String getUser_name() {
    return user_name;
    }

    public void setUser_name(String user_name) {
    this.user_name = user_name;
    }

    public String getUser_password() {
    return user_password;
    }

    public Long getUser_id() {
    return user_id;
    }

    public void setUser_id(Long user_id) {
    this.user_id = user_id;
    }

    public void setUser_password(String user_password) {
    this.user_password = user_password;
    }

    public Character getUser_state() {
    return user_state;
    }

    public void setUser_state(Character user_state) {
    this.user_state = user_state;
    }

}

前端展示页面

一个带有基本功能的展示页面,用Ajax的post方式提交表单数据,如果状态码等于200的话登陆成功,否则登陆失败,打印出登陆失败的信息并刷新验证码。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登陆界面</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>
</head>
<body>
    <h3>用户登陆</h3>
    <form action="LoginAction_login.do" id="form1" method="post">
        <table>
            <tr>
                <td><label for="username">用户名:</label></td>
                <td><input type="text" name="userName" id="username" /></td>
            </tr>
            <tr>
                <td><label for="password">密码:</label></td>
                <td><input type="password" name="password" id="password" /></td>
            </tr>
            <tr>
                <td><label for="verify">验证码:</label></td>
                <td><input type="text" name="verify" id="verify" /></td>
            </tr>
            <tr>
                <td></td>
                <td><img src="getVerifyAction.do" id="imgCode" /></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" /></td>
            </tr>
            </form>
        </table>
</body>
<script type="text/javascript">
    $(function() {
        $("#imgCode").click(function() {
            refreshCode();
        });

        $("#form1").submit(
                function() {
                    $.post("LoginAction_login.do", $("#form1").serialize(),
                            function(data) {
                                if (data.state == 200) {
                                    //跳转界面
                                    alert("success");
                                } else {
                                    alert(data.msg);
                                    refreshCode();
                                }

                            })
                    return false;
                })

    })
    //刷新验证码
    function refreshCode() {
        var url = "getVerifyAction.do?" + new Date().getTime(); //加时间戳防止缓存  
        $("#imgCode").attr("src", url);
    }
</script>
</html>

后端逻辑

首先是dao层,同过service层传入的用户名判断是否存在该用户,没有则返回null

  public User findUserByName(String name) {
    String sql = "from User where user_name = ?";
    List<User> lists = (List<User>) getHibernateTemplate().find(sql, name);
    if (lists.isEmpty()) {
        return null;
    }
    return lists.get(0);
    }

然后是service层,通过controller层传入的User 用户,然后通过判断是否存在该用户,没有则直接抛出异常。有则继续判断密码加密后是否相同。

  public void login(User u) {
    // TODO Auto-generated method stub
    User u1 = dao.findUserByName(u.getUser_name());
    if (u1 == null) {
        throw new RuntimeException("用户民不存在");
    }
    if (!u1.getUser_password().equals(MD5Utils.md5(u.getUser_password()))) {
        throw new RuntimeException("密码错误");
    }
    }

生成随机的数字,然后把随机数让入session中,输出到页面。注意验证码是一个独立的Action,直接在img标签的src属性中写入验证码的Action,就会生成验证码图片。或者直接在浏览器输入验证码的Action,就会出现验证码的图片。

  @Controller("getVerifyAction")
@Scope("prototype")
public class GetVerifyAction {

    /**
     * 设置验证码
     * 
     * @return
     * @throws IOException
     * @date 2017年10月15日 上午9:41:38
     */
    public String getVerifyImpage() throws IOException {
    HttpServletResponse response = ServletActionContext.getResponse();
    HttpServletRequest request = ServletActionContext.getRequest();
    response.setContentType("image/jpeg");
    response.setHeader("Pragma", "No-cache");
    response.setHeader("Cache-Control", "no-cache");
    response.setDateHeader("Expires", 0);
    HttpSession session = request.getSession();

    session.removeAttribute("verifyCode");
    int width = 70, height = 23;
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

    // 获取图形上下文
    Graphics g = image.getGraphics();
    // 生成随机类
    Random random = new Random();
    // 设定背景色
    g.setColor(getRandColor(200, 250));
    g.fillRect(0, 0, width, height);
    // 设定字体
    g.setFont(new Font("Times New Roman", Font.PLAIN, 20));
    // 画边框
    g.setColor(getRandColor(160, 200));
    g.drawRect(0, 0, width - 1, height - 1);
    // 随机产生100条干扰线
    g.setColor(getRandColor(160, 200));
    for (int i = 0; i < 100; i++) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(10);
        int yl = random.nextInt(10);
        g.drawLine(x, y, x + xl, y + yl);
    }
    // 取随机产生4位数字
    String sRand = "";
    for (int i = 0; i < 4; i++) {
        String rand = String.valueOf(random.nextInt(10));
        sRand += rand;

        g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));

        g.drawString(rand, 13 * i + 14, 20);
    }
    // 将认证码存入SESSION
    session.setAttribute("verifyCode", sRand);
    System.out.println("verifyCode:" + session.getAttribute("verifyCode"));
    // 图象生效
    g.dispose();
    // 输出图象到页面
    ImageIO.write(image, "JPEG", response.getOutputStream());
    return null;
    }

    private Color getRandColor(int fc, int bc) {// 给定范围获得随机颜色
    Random random = new Random();
    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);
    }
}

登陆的Action,首先判断前端传入的验证码是否和session中的验证相等。
相等则把前台传入的账号,密码封装到User实体中,传入到service中。当然也可以不封装,直接把用户名,密码传入service,前台参数少可以这么做。如果前台传入的参数很多的话,最好封装到相对应的实体类中,一方面是更能体现出相对对象的写法,另一方面是写出的代码更加利于维护和简洁。
调用完service层方法后,如果没有抛出异常,则说明用户名和密码匹配。如果不匹配,就会抛出相应的异常,并且捕捉到Map集合中。

public class LoginAction extends ActionSupport {

    @Autowired
    LoginService service;

    /**
     * 登陆
     * 
     * @return
     * @throws IOException
     * @date 2017年10月15日 下午5:42:47
     */
    public String login() throws IOException {
    Map m = new HashMap();
    boolean falg = ResultUtils.checkVerifyCode(verify);
    if (falg) {
        User u = new User();
        u.setUser_name(userName);
        u.setUser_password(password);
        try {
        service.login(u);
        m.put("state", Result.SUCCESS.getState());
        } catch (Exception e) {
        // TODO: handle exception
        String message = e.getMessage();
        m.put("state", Result.ERROR.getState());
        m.put("msg", message);
        }
    } else {
        m.put("state", Result.ERROR.getState());
        m.put("msg", "验证码错误");
    }
    //把Map集合转化为Json数据
    ResultUtils.toJson(ServletActionContext.getResponse(), m);
    return null;
    }

    private String userName;
    private String password;
    private Map<String, Object> jsonResult;
    private String verify;

    public String getVerify() {
    return verify;
    }

    public void setVerify(String verify) {
    this.verify = verify;
    }

    public Map<String, Object> getJsonResult() {
    return jsonResult;
    }

    public void setJsonResult(Map<String, Object> jsonResult) {
    this.jsonResult = jsonResult;
    }

    public String getUserName() {
    return userName;
    }

    public void setUserName(String userName) {
    this.userName = userName;
    }

    public String getPassword() {
    return password;
    }

    public void setPassword(String password) {
    this.password = password;
    }


}

枚举类型的结果集,创建通过整形初始化和字符串和整形初始化的构造器。比如当调用Result.SUCCESS(200),可以初始化一个state为200的对象。然后Result.SUCCESS(200).getState()就可以获取该参数。


public enum Result {

    SUCCESS(200), ERROR(400), INFO("请求超时", 100);
    private String msg;
    private int state;

    private Result(int state) {
    this.state = state;
    }

    private Result(String msg, int state) {
    this.msg = msg;
    this.state = state;
    }

    public String getMsg() {
    return msg;
    }

    public void setMsg(String msg) {
    this.msg = msg;
    }

    public int getState() {
    return state;
    }

    public void setState(int state) {
    this.state = state;
    }

}

MD5加密的工具类,传入相应的密码就会获取该密码的加密的字符串。


public class MD5Utils {
    /**
     * 使用md5的算法进行加密
     */
    public static String md5(String plainText) {
    byte[] secretBytes = null;
    try {
        secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes());
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("没有md5这个算法!");
    }
    String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
    // 如果生成数字未满32位,需要前面补0
    for (int i = 0; i < 32 - md5code.length(); i++) {
        md5code = "0" + md5code;
    }
    return md5code;
    }

    public static void main(String[] args) {
    System.out.println(md5("1234"));
    }

}

由于把对象转化为Json数据和检查验证码是否相等,在许多地方都能够用到,因此把大量重复的代码提取出来,制作成工具类。更加使代码简洁,优雅,也更能体现面对对象的思想。

public class ResultUtils {
    /**
     * 转化json数据
     * 
     * @date 2017年10月15日 下午4:03:29
     */
    public static void toJson(HttpServletResponse response, Object data) throws IOException {
    Gson gson = new Gson();
    String result = gson.toJson(data);
    response.setContentType("text/json; charset=utf-8");
    response.setHeader("Cache-Control", "no-cache"); // 取消浏览器缓存
    PrintWriter out = response.getWriter();
    out.print(result);
    out.flush();
    out.close();
    }

    /**
     * 验证验证码是否相等
     * 
     * @param originVerifyCode
     * @return
     * @date 2017年10月15日 上午9:47:30
     */
    public static boolean checkVerifyCode(String originVerifyCode) {
    HttpServletRequest request = ServletActionContext.getRequest();
    HttpSession session = request.getSession();
    String verifyCode = (String) session.getAttribute("verifyCode");
    if (originVerifyCode.equals(verifyCode)) {
        return true;
    }
    return false;
    }

}

展示效果

成功

这里写图片描述

密码错误

这里写图片描述

用户名不存在

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值