我们来实现添加店铺并且引入验证码的步骤
我们使用kaptcha库,首先在maven中加入这个api的包
首先在web.xml文件中配置:kaptcha的验证码。
<!-- 生成图片的Servlet,Kaptcha验证码 -->
<servlet>
<servlet-name>Kaptcha</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<!-- 是否有边框 -->
<init-param>
<param-name>kaptcha.border</param-name>
<param-value>no</param-value>
</init-param>
<!-- 字体颜色 -->
<init-param>
<param-name>kaptcha.textproducer.font.color</param-name>
<param-value>red</param-value>
</init-param>
<!-- 图片宽度 -->
<init-param>
<param-name>kaptcha.image.width</param-name>
<param-value>135</param-value>
</init-param>
<!-- 使用哪些字符生成验证码 -->
<init-param>
<param-name>kaptcha.textproducer.char.string</param-name>
<param-value>ACDEFHKPRSTWX345679</param-value>
</init-param>
<!-- 图片高度 -->
<init-param>
<param-name>kaptcha.image.height</param-name>
<param-value>50</param-value>
</init-param>
<!-- 字体大小 -->
<init-param>
<param-name>kaptcha.textproducer.font.size</param-name>
<param-value>43</param-value>
</init-param>
<!-- 干扰线的颜色 -->
<init-param>
<param-name>kaptcha.noise.color</param-name>
<param-value>black</param-value>
</init-param>
<!-- 字符个数 -->
<init-param>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>4</param-value>
</init-param>
<!-- 使用哪些字体 -->
<init-param>
<param-name>kaptcha.textproducer.font.names</param-name>
<param-value>Arial</param-value>
</init-param>
</servlet>
<!-- 映射的url -->
<servlet-mapping>
<servlet-name>Kaptcha</servlet-name>
<url-pattern>/Kaptcha</url-pattern>
</servlet-mapping>
配置他的显示格式和映射文件。
然后是前端的设计;
html中加入验证码选项:
<!-- 验证码 kapa-->
<li>
<div class="item-content">
<div class="item-inner">
<div class="item-title label">验证码</div>
<input type="text" id="j_kaptcha" placeholder="验证码">
<div class="item-input">
<img id="kaptcha_img" alt="点击更换" title="点击更换"
onclick="changeVerifyCode(this)" src="../Kaptcha"> <!-- src是找到web.xml中 对应的servlet的名字 -->
</div>
</div>
</div>
</li>
由于别的模块也会使用到验证码功能,我们将验证码的js存放在common文件夹下:这里存放公用的js
common.js
shopoperation.js:
// 验证码
var verifyCodeActual =$('#j_kaptcha').val();
if(!verifyCodeActual){
$.toast('请输入验证码');
return;
}
// 接收数据
var formData = new FormData();
// 和后端约定好,利用shopImg和 shopStr接收 shop图片信息和shop信息
formData.append('shopImg',shopImg);
// 转成JSON格式,后端收到后将JSON转为实体类
formData.append('shopStr',JSON.stringify(shop));
// 将数据封装到formData发送到后台
formData.append('verifyCodeActual',verifyCodeActual);
// 利用ajax提交
$.ajax({
// 动态判断 url
url:registerShopUrl,
type:'POST',
data:formData,
contentType:false,
processData:false,
cache:false,
success:function(data){
if(data.success){
$.toast('提示信息:'+data.errMsg);
}else{
$.toast('提示信息:' + data.errMsg);
}
// 点击提交后 不管成功失败都更换验证码,防止重复提交
$('#kaptcha_img').click();
}
});
});
最后是后台的实现:
思路:在提交的controller提交前,我们先判断验证码是否正确我们可以调用kaptcha的功能来获取当前session中的验证码,我们可以通过前台传来的验证码进行比较,判断是否为相同值。
先写一个工具类用于判断验证码是否相同。
package storepro.util;
import com.google.code.kaptcha.Constants;
import javax.servlet.http.HttpServletRequest;
public class CodeUtil {//判断验证码是否相同
public static boolean checkVerifyCode(HttpServletRequest request)
{
String verifyCodeExpect= (String) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
String verifyCodeActual=HttpServletRequestUtil.getString(request,"verifyCodeActual");
if (verifyCodeActual==null&&!verifyCodeActual.equals(verifyCodeExpect))//当实际值为空或者实际值和期望值不同
return false;//返回错误
return true;
}
}
通过之前写的HttpServletRequest里的方法获取相应的key值,从中取出相应的数据,,判断是否相同
加入:
private Map<String,Object> registerShop(HttpServletRequest request){
Map<String,Object> modelMap=new HashMap<String,Object>();
//先判断验证码是否正确
if (!CodeUtil.checkVerifyCode(request)){//当验证码错误时
modelMap.put("success",false);
modelMap.put("errMsg","输入了错误的验证码");
return modelMap;
}
//1.接受转换相应的参数,包括店铺信息和店铺图片信息
String shopStr = HttpServletRequestUtil.getString(request,"shopStr");//通过转换工具类将前端传来的数据转为字符串
ObjectMapper mapper=new ObjectMapper();//获取处理json的对象
Shop shop=null;
try{
shop=mapper.readValue(shopStr,Shop.class);//将传入的jsonshopStr转为Shop对象并完成赋值
}catch (Exception e){//出错后输出错误信息
modelMap.put("success",false);
modelMap.put("errMsg",e.getMessage());
return modelMap;
}
/*
* 操作添加图片
* */
CommonsMultipartFile shopImg=null;//spring自带
CommonsMultipartResolver commonsMultipartResolver=new CommonsMultipartResolver(
request.getSession().getServletContext()
);//解析request传来的文件的,通过本次会话的上下文获取相关文件上传的内容
if (commonsMultipartResolver.isMultipart((request))) {//如果有上传的文件流
MultipartHttpServletRequest multipartHttpServletRequest= (MultipartHttpServletRequest) request;//这样就能提取出request中的文件流了
shopImg=(CommonsMultipartFile)multipartHttpServletRequest.getFile("shopImg");//(这个字符串"shopImg"是前端传来的),得到文件
}else {//如果不具备图片
modelMap.put("success",false);
modelMap.put("errMsg","上传图片不能为空");
return modelMap;
}
// 2.注册店铺
if (shop!=null&&shopImg!=null) {//如果接受完相应的参数
PersonInfo owner=new PersonInfo();//owner的信息可以通过session获取
owner.setUserId(1L);//先手动设置,后期更改
shop.setOwner(owner);
ShopExecution shopExecution= null;//不能直接传文件,因为CommonsMultipartFile和File不能直接转换
try {
shopExecution = shopService.addShop(shop,shopImg.getInputStream(),shopImg.getOriginalFilename());
} catch (IOException e) {
e.printStackTrace();
}
if (shopExecution.getState()== ShopStateEnum.CHECK.getState()){//如果操作成功
modelMap.put("success",true);
}else {
modelMap.put("success",false);
modelMap.put("errMsg",shopExecution.getState());
return modelMap;
}
return modelMap;
}else{
modelMap.put("success",false);
modelMap.put("errMsg","请输入店铺信息");
return modelMap;
}
//3.返回结果
}
}
判断验证码部分,如果相同接着进行,如果不同任务结束。这个方法在的url在js中:
/**
* submit按钮触发的操作
* 验证表单输入,省略。。。。
*/
$('#submit').click(function() {
// 获取页面的值
var shop = {};
// 注意: 这个地方的变量名称要和Shop实体类中的属性保持一致,因为后台接收到shopStr后,会将Json转换为实体类,如果不一致会抛出异常
// com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException
// 如果是编辑,需要传入shopId
shop.shopName = $('#shop-name').val();
shop.shopAddr = $('#shop-addr').val();
shop.phone = $('#shop-phone').val();
shop.shopDesc = $('#shop-desc').val();
// 选择id,双重否定=肯定
shop.shopCategory = {
// 这里定义的变量要和ShopCategory.shopCategoryId保持一致,否则使用databind转换会抛出异常
shopCategoryId:$('#shop-category').find('option').not(function(){
return !this.selected;
}).data('id')
};
shop.area = {
// 这里定义的变量要和Area.areaId属性名称保持一致,否则使用databind转换会抛出异常
areaId:$('#shop-area').find('option').not(function(){
return !this.selected;
}).data('id')
};
// 图片
var shopImg = $('#shop-img')[0].files[0];
// 验证码
var verifyCodeActual =$('#j_kaptcha').val();
if(!verifyCodeActual){
$.toast('请输入验证码');
return;
}
// 接收数据
var formData = new FormData();
// 和后端约定好,利用shopImg和 shopStr接收 shop图片信息和shop信息
formData.append('shopImg',shopImg);
// 转成JSON格式,后端收到后将JSON转为实体类
formData.append('shopStr',JSON.stringify(shop));
// 将数据封装到formData发送到后台
formData.append('verifyCodeActual',verifyCodeActual);
// 利用ajax提交
$.ajax({
// 动态判断 url
url:registerShopUrl,
type:'POST',
data:formData,
contentType:false,
processData:false,
cache:false,
success:function(data){
if(data.success){
$.toast('提示信息:'+data.errMsg);
}else{
$.toast('提示信息:' + data.errMsg);
}
// 点击提交后 不管成功失败都更换验证码,防止重复提交
$('#kaptcha_img').click();
}
});
});
});
注意前台通过formDate.append("key","value)方法传送数据,后台通过requset.getParamet("key")获得内容
这样整个店铺注册就实现了。可是进行了测试debug测试后,我发现前台传来的数据为空
解决:
因为我们的注册店铺页面有文件类型上传,所以必须配置文件上传解析器,才能正确接受request中的key值,就算我们一开始没有用到文件,spring看到有文件上传类型发现没有文件上传解析器,还是没办法识别key
加上文件上传解析器 在spring——web中
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--默认字符集编码-->
<property name="defaultEncoding" value="utf-8"></property>
<!-- 设置上传文件最大尺寸,1024*1024*20-->
<property name="maxUploadSize" value="20971520" />
<!--最大内存-->
<property name="maxInMemorySize" value="20971520"></property>
</bean>
问题解决