项目常用模块之异步登录

1.界面

使用了FreeMarker+jQuery form+Bootstrap,完成异步提交表单登录,出错后异步提示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content= "width=device-width, initial-scale=1.0">
<meta name="description" content= "">
<meta name="author" content= "Mosaddek">
<meta name="keyword"
     content= "FlatLab, Dashboard, Bootstrap, Admin, Template, Theme, Responsive, Fluid, Retina">

<title>师说CMS 后台</title>

<!-- Bootstrap core CSS -->
<link href=" ${BASE_PATH}/static/manage/css/bootstrap.min.css"
     rel=" stylesheet">
<link href=" ${BASE_PATH}/static/manage/css/bootstrap-reset.css"
     rel=" stylesheet">
<!--external css-->
<link
     href=" ${BASE_PATH}/static/manage/assets/font-awesome/css/font-awesome.css"
     rel=" stylesheet" />
<!-- Custom styles for this template -->
<link href=" ${BASE_PATH}/static/manage/css/style.css" rel="stylesheet" >
<link href=" ${BASE_PATH}/static/manage/css/style-responsive.css"
     rel=" stylesheet" />

<!-- HTML5 shim and Respond.js IE8 support of HTML5 tooltipss and media queries -->
<!--[if lt IE 9]>
    <script src="${BASE_PATH}/static/manage/js/html5shiv.js"></script>
    <script src="${BASE_PATH}/static/manage/js/respond.min.js"></script>
    <![endif]-->
<script src=" ${BASE_PATH}/static/manage/js/jquery.js" ></script>
<script src="${BASE_PATH} /static/manage/js /jquery.form.min.js"></script>
<style type="text/css" >
p.error {
     color: #DE5959;
}

.form-signin input[type="text"].error, .form- signin input[type="password"].error
     {
     border-color: #b94a48;
     color: #b94a48;
     - webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
     box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}

input.error:focus {
     border-color: #953b39;
     color: #b94a48;
     - webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px
           #d59392;
     box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
}
</style>
</head>

<body class="login-body">

     <div class="container" >

            <form class="form-signin" id="adminForm"
                action= "${BASE_PATH} /admin/login.json" autocomplete="off"
                method= "post">
                 <h2 class="form-signin-heading" >
                      <img src="${TEMPLATE_BASE_PATH} /images/logo.png"
                           style= "height: 38px;" />
                 </h2>
                 <div class="login-wrap">
                      <div class="form-group">
                                      <label for="exampleInputEmail1">用户名 </label>
                                      <input type="text" name="name" class="form-control" placeholder="用户名" value= "" style="*width: 250px;" autofocus>
                                  </div>
                      <div class="form-group">
                                      <label for="exampleInputEmail1">密码 </label>
                                      <input type="password" name="password" class="form-control" placeholder="密码" value= "" style="*width: 250px;">
                                  </div>                                         
                      <div class="form-group">
                            <input type="text" name= "captcha " class="form-control"
                                placeholder= "验证码" style="width: 100px; float: left;" > <img
                                id= "captcha "
                                style= "cursor: pointer; cursor: hand; margin-top: -13px;"
                                 οnclick="this.src='${BASE_PATH} /admin/captcha.htm?'+Math.random();"
                                 src=" ${BASE_PATH}/admin/captcha.htm" >
                      </div>
                      <div class="clearfix" ></div>
                      <div>
                            <p class="error" for= "captcha " style="display: none;"></p>
                      </div>
                      <button class="btn btn-lg btn-login btn-block" type="submit" >登录 </button>
                 </div>
            </form>

     </div>
     <script type="text/ javascript">
           /**
            * 显示表单的错误提示
            * @param id 表单ID
            * @param errors 错误列表
            */
           function showErrors(id, errors) {
                id.find('p[class=error]').hide();
                id.find('input,select').removeClass("error");
                for ( var name in errors) {
                      var e = id.find('p[for=' + name + ']');
                     id.find('input[name=' + name + '],select[name=' + name + ']')
                                .addClass("error");
                     if (e.length == 0) {
                           id.find(
                                     'input[name=' + name + '],select[name=' + name
                                                + ']').after(
                                     ' <p for="'+name+'" class="error"></p>');
                           e = id.find('p[for=' + name + ']');
                     }
                     if (errors[name] != "") {
                           e.html(errors[name]);
                           e.show();
                     }
                }
           }
           $(function() {
                $('#adminForm')
                           .ajaxForm(
                                     {
                                           dataType : 'json',
                                           success : function(data) {
                                                if (data.result) {
                                                     location.href = "${BASE_PATH}/manage/article/list.htm";
                                                } else {
                                                     showErrors($('#adminForm'), data.errors);
                                                     if (data.msg == "change_captcha") {
                                                          $('# captcha'). attr(
                                                                      " src",
                                                                      " ${BASE_PATH}/admin/captcha.htm?"
                                                                                + Math.random());
                                                           $(
                                                                      '#adminForm input[name="captcha"]')
                                                                      .val('');
                                                     }
                                                }
                                           }
                                     });
           });
     </script>
</body>
</html>

2.后台Controller

   界面与后台的交互,异步处理方法
@ResponseBody
     @RequestMapping(value = "/login.json", method = RequestMethod.POST)
     public JsonVo<String> adminLogin( @RequestParam(value = "name") String name,
                 @RequestParam(value = "password") String password,
                 @RequestParam(value = "captcha") String captcha,
                HttpServletRequest request, ModelMap modelMap) {
           JsonVo<String> json = new JsonVo<String>();

            try {
                String kaptcha = (String) request.getSession().getAttribute(
                          com.google.code.kaptcha.Constants. KAPTCHA_SESSION_KEY);
                 if (StringUtils. isBlank(password)) {
                     json.getErrors().put( "password", "密码不能为空" );
                } else if (password.length() < 6 || password.length() > 30) {
                     json.getErrors().put( "password", "密码最少6个字符,最多30个字符" );
                }
                 // 校验验证码
                 if (StringUtils. isNotBlank(kaptcha)
                           && kaptcha.equalsIgnoreCase(captcha)) {

                } else {
                     json.getErrors().put( "captcha", "验证码错误" );
                }
                json.check();

                 adminService.adminLogin(name, password, request);

           } catch (Exception e) {
                 // 异常,重置验证码
                request.getSession().removeAttribute(
                          com.google.code.kaptcha.Constants. KAPTCHA_SESSION_KEY);
                json.setResult( false);
                json.getErrors().put( "password", "邮箱或密码错误" );
                json.setMsg( "change_captcha");
           }
            return json;
     }

     /**
      * 生成验证码
      *
      * @param request
      * @param response
      * @throws Exception
      */
     @RequestMapping(value = "captcha.htm", method = RequestMethod.GET)
     public void captcha(HttpServletRequest request, HttpServletResponse response)
                 throws Exception {
           response.setDateHeader( "Expires", 0);
           response.setHeader( "Cache-Control",
                      "no-store, no-cache, must-revalidate");
           response.addHeader( "Cache-Control", "post-check=0, pre-check=0");
           response.setHeader( "Pragma", "no-cache");
           response.setContentType( "image/jpeg");
           String capText = captchaProducer.createText();
           request.getSession().setAttribute(
                     com.google.code.kaptcha.Constants. KAPTCHA_SESSION_KEY, capText);
           BufferedImage bi = captchaProducer.createImage(capText);
           ServletOutputStream out = response.getOutputStream();
           ImageIO. write(bi, "jpg", out);
            try {
                out.flush();
           } finally {
                out.close();
           }
     }


3.后台逻辑与验证


/**
      * 管理员登陆
      *
      * @param email
      * @param password
      * @param request
      * @throws IOException
      */
     public void adminLogin(String name, String password,
                HttpServletRequest request) throws AuthException,
                IOException {
           AdminVo admin = adminDao.getAdminByName(name);
            if (admin == null) {
                 throw new AuthException( "邮箱或密码错误" );
           }
           String loginPassword = AuthUtils.getPassword(password);
            if (loginPassword.equals(admin.getPassword())) {
                HttpSession session = request.getSession();
                admin.setPassword( "");
                 if (name.equals(PropertyUtils
                           . getValue("shishuocms.admin"))) {
                     admin.setAdmin( true);
                } else {
                     admin.setAdmin( false);
                }
                session.setAttribute(SystemConstant. SESSION_ADMIN,
                           admin);
           } else {
                 throw new AuthException( "邮箱或密码错误" );
           }
     }


4.自定义的JsonVo

import java.util.HashMap;

import org.codehaus.jackson.map.annotate.JsonSerialize;

@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class JsonVo<T> {
	/**
	 * 结果
	 */
	private boolean result;
	/**
	 * 成功的消息
	 */
	private String msg;

	/**
	 * 具体每个输入错误的消息
	 */
	private HashMap<String, String> errors = new HashMap<String, String>();

	/**
	 * 返回的数据
	 */
	private T t;

	public boolean isResult() {
		return result;
	}

	public void setResult(boolean result) {
		this.result = result;
	}

	public String getMsg() {
		return msg;
	}

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

	public HashMap<String, String> getErrors() {
		return errors;
	}

	public void setErrors(HashMap<String, String> errors) {
		this.errors = errors;
	}

	public T getT() {
		return t;
	}

	public void setT(T t) {
		this.t = t;
	}

	public void check() throws ValidateException {
		if (this.getErrors().size() > 0) {
			this.setResult(false);
			throw new ValidateException("有错误发生");
		} else {
			this.setResult(true);
		}
	}
}


5.流程总结

    1.前端通过ajax方式提交表单,根据后台返回的信息,确认登录,or 显示错误提示
    2.后台接收form参数后,调用Service进行处理,通过自定义类似Map的对象,将要提示的信息封装后返回给前端(包括后台验证的提示信息,与逻辑处理的提示信息)
    3.Service进行逻辑处理,出错时抛出自定义异常,Controller来处理抛出的异常
    4.与逻辑无关的验证码,可通过单独的Servlet来生成,然后返回给前端页面(使用Google的kaptcha.jar或自定义验证码的生成类)
       自定义验证码生成

       1.自定义生成验证码高级工具类  --  可指定验证码生成的长度和生成图片的大小
         
import java.awt.Color;  
import java.awt.Font;  
import java.awt.Graphics;  
import java.awt.Graphics2D;  
import java.awt.LinearGradientPaint;  
import java.awt.Paint;  
import java.awt.RenderingHints;  
import java.awt.geom.AffineTransform;  
import java.awt.image.BufferedImage;  
import java.io.File;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.OutputStream;  
import java.util.Arrays;  
import java.util.Random;  
  
import javax.imageio.ImageIO;  
  
public class VerifyCodeUtils{  
  
    //使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符  
    public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";  
    private static Random random = new Random();  
  
  
    /** 
     * 使用系统默认字符源生成验证码 
     * @param verifySize    验证码长度 
     * @return 
     */  
    public static String generateVerifyCode(int verifySize){  
        return generateVerifyCode(verifySize, VERIFY_CODES);  
    }  
    /** 
     * 使用指定源生成验证码 
     * @param verifySize    验证码长度 
     * @param sources   验证码字符源 
     * @return 
     */  
    public static String generateVerifyCode(int verifySize, String sources){  
        if(sources == null || sources.length() == 0){  
            sources = VERIFY_CODES;  
        }  
        int codesLen = sources.length();  
        Random rand = new Random(System.currentTimeMillis());  
        StringBuilder verifyCode = new StringBuilder(verifySize);  
        for(int i = 0; i < verifySize; i++){  
            verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));  
        }  
        return verifyCode.toString();  
    }  
      
    /** 
     * 生成随机验证码文件,并返回验证码值 
     * @param w 
     * @param h 
     * @param outputFile 
     * @param verifySize 
     * @return 
     * @throws IOException 
     */  
    public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{  
        String verifyCode = generateVerifyCode(verifySize);  
        outputImage(w, h, outputFile, verifyCode);  
        return verifyCode;  
    }  
      
    /** 
     * 输出随机验证码图片流,并返回验证码值 
     * @param w 
     * @param h 
     * @param os 
     * @param verifySize 
     * @return 
     * @throws IOException 
     */  
    public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{  
        String verifyCode = generateVerifyCode(verifySize);  
        outputImage(w, h, os, verifyCode);  
        return verifyCode;  
    }  
      
    /** 
     * 生成指定验证码图像文件 
     * @param w 
     * @param h 
     * @param outputFile 
     * @param code 
     * @throws IOException 
     */  
    public static void outputImage(int w, int h, File outputFile, String code) throws IOException{  
        if(outputFile == null){  
            return;  
        }  
        File dir = outputFile.getParentFile();  
        if(!dir.exists()){  
            dir.mkdirs();  
        }  
        try{  
            outputFile.createNewFile();  
            FileOutputStream fos = new FileOutputStream(outputFile);  
            outputImage(w, h, fos, code);  
            fos.close();  
        } catch(IOException e){  
            throw e;  
        }  
    }  
      
    /** 
     * 输出指定验证码图片流 
     * @param w 
     * @param h 
     * @param os 
     * @param code 
     * @throws IOException 
     */  
    public static void outputImage(int w, int h, OutputStream os, String code) throws IOException{  
        int verifySize = code.length();  
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);  
        Random rand = new Random();  
        Graphics2D g2 = image.createGraphics();  
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);  
        Color[] colors = new Color[5];  
        Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN,  
                Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,  
                Color.PINK, Color.YELLOW };  
        float[] fractions = new float[colors.length];  
        for(int i = 0; i < colors.length; i++){  
            colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];  
            fractions[i] = rand.nextFloat();  
        }  
        Arrays.sort(fractions);  
          
        g2.setColor(Color.GRAY);// 设置边框色  
        g2.fillRect(0, 0, w, h);  
          
        Color c = getRandColor(200, 250);  
        g2.setColor(c);// 设置背景色  
        g2.fillRect(0, 2, w, h-4);  
          
        //绘制干扰线  
        Random random = new Random();  
        g2.setColor(getRandColor(160, 200));// 设置线条的颜色  
        for (int i = 0; i < 20; i++) {  
            int x = random.nextInt(w - 1);  
            int y = random.nextInt(h - 1);  
            int xl = random.nextInt(6) + 1;  
            int yl = random.nextInt(12) + 1;  
            g2.drawLine(x, y, x + xl + 40, y + yl + 20);  
        }  
          
        // 添加噪点  
        float yawpRate = 0.05f;// 噪声率  
        int area = (int) (yawpRate * w * h);  
        for (int i = 0; i < area; i++) {  
            int x = random.nextInt(w);  
            int y = random.nextInt(h);  
            int rgb = getRandomIntColor();  
            image.setRGB(x, y, rgb);  
        }  
          
        shear(g2, w, h, c);// 使图片扭曲  
  
        g2.setColor(getRandColor(100, 160));  
        int fontSize = h-4;  
        Font font = new Font("Algerian", Font.ITALIC, fontSize);  
        g2.setFont(font);  
        char[] chars = code.toCharArray();  
        for(int i = 0; i < verifySize; i++){  
            AffineTransform affine = new AffineTransform();  
            affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2);  
            g2.setTransform(affine);  
            g2.drawChars(chars, i, 1, ((w-10) / verifySize) * i + 5, h/2 + fontSize/2 - 10);  
        }  
          
        g2.dispose();  
        ImageIO.write(image, "jpg", os);  
    }  
      
    private static 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 static int getRandomIntColor() {  
        int[] rgb = getRandomRgb();  
        int color = 0;  
        for (int c : rgb) {  
            color = color << 8;  
            color = color | c;  
        }  
        return color;  
    }  
      
    private static int[] getRandomRgb() {  
        int[] rgb = new int[3];  
        for (int i = 0; i < 3; i++) {  
            rgb[i] = random.nextInt(255);  
        }  
        return rgb;  
    }  
  
    private static void shear(Graphics g, int w1, int h1, Color color) {  
        shearX(g, w1, h1, color);  
        shearY(g, w1, h1, color);  
    }  
      
    private static void shearX(Graphics g, int w1, int h1, Color color) {  
  
        int period = random.nextInt(2);  
  
        boolean borderGap = true;  
        int frames = 1;  
        int phase = random.nextInt(2);  
  
        for (int i = 0; i < h1; i++) {  
            double d = (double) (period >> 1)  
                    * Math.sin((double) i / (double) period  
                            + (6.2831853071795862D * (double) phase)  
                            / (double) frames);  
            g.copyArea(0, i, w1, 1, (int) d, 0);  
            if (borderGap) {  
                g.setColor(color);  
                g.drawLine((int) d, i, 0, i);  
                g.drawLine((int) d + w1, i, w1, i);  
            }  
        }  
  
    }  
  
    private static void shearY(Graphics g, int w1, int h1, Color color) {  
  
        int period = random.nextInt(40) + 10; // 50;  
  
        boolean borderGap = true;  
        int frames = 20;  
        int phase = 7;  
        for (int i = 0; i < w1; i++) {  
            double d = (double) (period >> 1)  
                    * Math.sin((double) i / (double) period  
                            + (6.2831853071795862D * (double) phase)  
                            / (double) frames);  
            g.copyArea(i, 0, 1, h1, 0, (int) d);  
            if (borderGap) {  
                g.setColor(color);  
                g.drawLine(i, (int) d, i, 0);  
                g.drawLine(i, (int) d + h1, i, h1);  
            }  
  
        }  
  
    }  
//    public static void main(String[] args) throws IOException{  
//        File dir = new File("F:/verifies");  
//        int w = 200, h = 80;  
//        for(int i = 0; i < 50; i++){  
//            String verifyCode = generateVerifyCode(4);  
//            File file = new File(dir, verifyCode + ".jpg");  
//            outputImage(w, h, file, verifyCode);  
//        }  
//    }  
} 

      
2.Controller或单独的Servlet去生成验证码
        1.Controller方式
          
@RequestMapping(value = "getCode.htm",method=RequestMethod.GET)
	public void getCode(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String code = VerifyCodeUtils.generateVerifyCode(4);
		request.getSession().setAttribute("img_code", code);
		VerifyCodeUtils.outputImage(96, 33, response.getOutputStream(), code);
	}

        2.Servlet方式,需要在web.xml中配置单独的获取url路径
         

import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

import com.alexgaoyh.admin.login.shiro.captcha.CaptchaUtil;
import com.alexgaoyh.admin.login.shiro.captcha.constant.CaptchaConstant;

/**
 * 验证码servlet
 * @author Administrator
 *
 */
public class CaptchaServlet extends HttpServlet {
	
	private static final Logger LOGGER = Logger.getLogger(CaptchaServlet.class);

	private static final long serialVersionUID = -124247581620199710L;
         
        //通过自定义的<span style="font-family: Arial, Helvetica, sans-serif;">VerifyCodeUtils生成并输出验证码</span>
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
<pre name="code" class="java"><pre name="code" class="java">               // 设置相应类型,告诉浏览器输出的内容为图片
		resp.setContentType("image/jpeg");
		// 不缓存此内容
		resp.setHeader("Pragma", "No-cache");
		resp.setHeader("Cache-Control", "no-cache");
		resp.setDateHeader("Expire", 0);
 
 
 
                String code = VerifyCodeUtils.generateVerifyCode(4);
		req.getSession().setAttribute("img_code", code);
		VerifyCodeUtils.outputImage(96, 33, resp.getOutputStream(), code);
}
 
 
        //通过Google的kaptcha.jar生成验证码
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		//doGet(req, resp);
            <pre name="code" class="java">               // 设置相应类型,告诉浏览器输出的内容为图片
		resp.setContentType("image/jpeg");
		// 不缓存此内容
		resp.setHeader("Pragma", "No-cache");
		resp.setHeader("Cache-Control", "no-cache");
		resp.setDateHeader("Expire", 0);
		try {

			HttpSession session = req.getSession();

			CaptchaUtil tool = new CaptchaUtil();
			StringBuffer code = new StringBuffer();
			BufferedImage image = tool.genRandomCodeImage(code);
			session.removeAttribute(CaptchaConstant.KEY_CAPTCHA);
			session.setAttribute(CaptchaConstant.KEY_CAPTCHA, code.toString());

			// 将内存中的图片通过流动形式输出到客户端
			ImageIO.write(image, "JPEG", resp.getOutputStream());

		} catch (Exception e) {
			LOGGER.info("context", e);
		}
}
}
 
 
3.前台获取验证码
    
 <form id="loginForm" name="loginForm" method="post">
                <div class="name">
                    <label>用户名</label><input type="text" class="text" id="username" placeholder="用户名" name="username" tabindex="1">
                    <label>密 码</label><input type="password" class="text" id="password" placeholder="密码" name="password" tabindex="2">
                    <label>验证码</label><input type="text" class="text" id="code" placeholder="验证码" name="code" tabindex="3">
                    <img alt="" src="${ctx }/getCode.htm" id="code_img">
                    <input type="button" class="regist" tabindex="4" value="登录" id="login_submit">
                    <!-- <input type="checkbox" name="rememberMe" id="remember_me">记住我 -->
                    <div class="check"></div>
            </div>
                <div class="tip"></div>
                </form>
$("#code_img").click(function() {
<span style="white-space:pre">		</span>$(this).attr("src", ctx+'/getCode.htm?' + Math.random());
<span style="white-space:pre">	</span>});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值