简介
在获取图形验证码和短信验证码有很多重复的代码本次会优化这些代码。
项目文件结构
验证码处理器代码结构
虚线是调用
- ValidateCodeController # 服务入口
- ValidateCodeProcessor # 验证码处理接口
- AbstractValidateCodeProcessor # 验证码处理 公共功能,使用模版方法模式聚合公共逻辑
- ImageCodeProcessor # 图片验证码处理:响应
- SmsCodeProcessor # 短信验证码处理:发送
- ValidateCodeGenerator # 生成接口
- ImageCodeGenerate # 图形验证码生成
- SmsCodeGenerator # 短信验证码生成
ValidateCodeProcessor
com.spring.security.validate.code路径创建ValidateCodeProcessor类,生成验证码入口
package com.spring.security.validate.code;
import org.springframework.web.context.request.ServletWebRequest;
/**
* 校验码处理器,封装不同校验码的处理逻辑
*
*/
public interface ValidateCodeProcessor {
/**
* 验证码放入session时的前缀
*/
String SESSION_KEY_PREFIX = "SESSION_KEY_FOR_CODE_";
/**
* 创建校验码
*
* @param request
* @throws Exception
*/
void createCode(ServletWebRequest request) throws Exception;
}
AbstractValidateCodeProcessor
验证码处理 公共功能,使用模版方法模式聚合公共逻辑
com.spring.security.validate.code.impl路径创建AbstractValidateCodeProcessor类
package com.spring.security.validate.code.impl;
import java.util.Map;
import com.spring.security.validate.code.ValidateCodeException;
import org.apache.commons.lang.StringUtils;
import com.spring.security.validate.code.ValidateCode;
import com.spring.security.validate.code.ValidateCodeGenerator;
import com.spring.security.validate.code.ValidateCodeProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.context.request.ServletWebRequest;
public abstract class AbstractValidateCodeProcessor<C extends ValidateCode> implements ValidateCodeProcessor {
/**
* 操作session的工具类
*/
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
/**
* 收集系统中所有的 {@link ValidateCodeGenerator} 接口的实现。
*/
@Autowired
private Map<String, ValidateCodeGenerator> validateCodeGenerators;
/**
* ValidateCodeProcessor
*/
@Override
public void createCode(ServletWebRequest request) throws Exception {
C validateCode = generate(request);
save(request, validateCode);
send(request, validateCode);
}
/**
* 生成校验码
*
* @param request
* @return
*/
@SuppressWarnings("unchecked")
private C generate(ServletWebRequest request) {
String type = getProcessorType(request);
ValidateCodeGenerator validateCodeGenerator = validateCodeGenerators.get(type + "CodeGenerator");
if (validateCodeGenerator == null) {
throw new ValidateCodeException("验证码生成器" + type + "CodeGenerator不存在");
}
return (C) validateCodeGenerator.createCode(request);
}
/**
* 保存校验码
*
* @param request
* @param validateCode
*/
private void save(ServletWebRequest request, C validateCode) {
sessionStrategy.setAttribute(request, SESSION_KEY_PREFIX + getProcessorType(request).toUpperCase(), validateCode);
}
/**
* 发送校验码,由子类实现
*
* @param request
* @param validateCode
* @throws Exception
*/
protected abstract void send(ServletWebRequest request, C validateCode) throws Exception;
/**
* 根据请求的url获取校验码的类型
*
* @param request
* @return
*/
private String getProcessorType(ServletWebRequest request) {
return StringUtils.substringAfter(request.getRequest().getRequestURI(), "/code/");
}
}
ImageCodeProcessor
com.spring.security.validate.code.image路径创建ImageCodeProcessor图片验证码处理:响应
/**
*
*/
package com.spring.security.validate.code.image;
import javax.imageio.ImageIO;
import com.spring.security.validate.code.impl.AbstractValidateCodeProcessor;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.ServletWebRequest;
/**
* 图片验证码处理器
*
*/
@Component("imageCodeProcessor")
public class ImageCodeProcessor extends AbstractValidateCodeProcessor<ImageCode> {
/**
* 发送图形验证码,将其写到响应中
*/
@Override
protected void send(ServletWebRequest request, ImageCode imageCode) throws Exception {
ImageIO.write(imageCode.getImage(), "JPEG", request.getResponse().getOutputStream());
}
}
SmsCodeProcessor
com.spring.security.validate.code.sms路径创建SmsCodeProcessor短信验证码处理:发送
/**
*
*/
package com.spring.security.validate.code.sms;
import com.spring.security.validate.code.ValidateCode;
import com.spring.security.validate.code.impl.AbstractValidateCodeProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
/**
* 短信验证码处理器
*
*/
@Component("smsCodeProcessor")
public class SmsCodeProcessor extends AbstractValidateCodeProcessor<ValidateCode> {
/**
* 短信验证码发送器
*/
@Autowired
private SmsCodeSender smsCodeSender;
@Override
protected void send(ServletWebRequest request, ValidateCode validateCode) throws Exception {
//获取手机号
String mobile = ServletRequestUtils.getRequiredStringParameter(request.getRequest(), "mobile");
//发送短信
smsCodeSender.send(mobile, validateCode.getCode());
}
}
修改控制器
改造ValidateController类统一访问路径
package com.spring.security.validate.code;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* 获取验证码控制器
*/
@RestController
public class ValidateController {
@Autowired
private Map<String, ValidateCodeProcessor> validateCodeProcessor;
/**
* 创建验证码,根据验证码类型不同,调用不同的 {@link ValidateCodeProcessor}接口实现
*
* @param request
* @param response
* @param type
* @throws Exception
*/
@GetMapping("/code/{type}")
public void createCode(HttpServletRequest request, HttpServletResponse response, @PathVariable String type)
throws Exception {
validateCodeProcessor.get(type + "CodeProcessor").createCode(new ServletWebRequest(request, response));
}
}
修改图形验证码拦截器
修改ValidateCodeFilter类的validateCode方法:
ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, "SESSION_KEY_FOR_CODE_IMAGE");
session值我们先写死,等做到短信验证码拦截器一起优化掉。
测试
启动项目访问:http://127.0.0.1:8080/signIn.html
获取图形验证码没问题,输入正确验证码账号登录:
重启项目测试获取短信验证:
来源:oschina
链接:https://my.oschina.net/u/1046143/blog/3187795