上一节,我们已经将基本环境配置完成,接下来正式整合
1. 将项目前端代码页面载入
2. 功能分析
2.1 register.html
- 使用 js完成表单验证,即鼠标离开输入框就判断输入是否合法
- 使用ajax完成表单提交
- 注册成功,跳转到成功页面
2.2 web层
- 获取表单提交数据
- 封装User对象
- 调用service完成注册
- 根据返回,提示信息
成功 即跳转
不成功,提示用户已存在
2.3 service层
- 调用mapper层根据用户名查询用户
存在,返回false
不存在,调用mapper保存用户信息
2.4 UserMapper层
- Boolean findByUserName(String username);
- void saveUser(User user);
3. register.html
这是整个regiester.html需要验证的,只需要将每个跳转改成对应的路径即可
4. SSM整合
4.1 工厂整合
将session工厂交给Spring容器管理,只需要从容器中获取执行操作的Mapper实例即可
applicationContext.xml
<!--加载jdbc.properties-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置mybatis的sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
</bean>
<!--扫描Mapper,让Spring容器产生Mapper类-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ssmtravel.mapper"/>
</bean>
4.2 事务控制
将事务控制交给spring容器进行声明式事务控制
applicationContext.xml
......
......
......
<!--头部添加命名空间,粘贴其他的,直接修改相应的名字即可-->
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
......
......
......
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
......
......
......
......
......
......
<!--配置声明式事务控制-->
<!--平台事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务增强-->
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 切点表达式-->
<!--* com.ssmtravel.service.Impl.*.*(..)
public :修饰符省略
*: 返回值类型、包名、类名、方法名可以使用星号* 代表任意
..:参数列表可以使用两个点 .. 表示任意个数,任意类型的参数列表
包名与类名之间一个点 . 代表当前包下的类,两个点 .. 表示当前包及其子包下的类
-->
<!--事务织入-->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.ssmtravel.service.Impl.*.*(..))"/>
</aop:config>
5. 验证用户名是否存在
只有这个是需要访问后端,其他验证均只是简单验证。
5.1 register.html
// *********************************** 验证用户名 ***********************************
var username = document.getElementById("username");
username.onblur = function () {
xiaoyan_username();
}
function xiaoyan_username() {
//2.定义正则
var reg_username = /^\w{8,20}$/;
//3.判断,给出提示信息
var flag = reg_username.test(username.value);
if (flag) {
//用户名合法
$("#username").css("border", "");
$.ajax({
type:'POST',
url:"/ssm-travel/user/selectByUserName",
data:"username="+username.value,
dataType:"json",
success: function(data) {
if(data == "success"){
$("#errorMsg").css("visibility","hidden");
$("#username").css("border", "");
}else{
$("#username").css("border", "1px solid red");
// username.value="用户名已经存在"; //让用户名输入框为空
$("#errorMsg").css("visibility","visible");
$("#errorMsg").html(data)
$("#username").focus();//把焦点给用户名输入框
flag = false
}
}
});
} else {
//用户名非法,加一个红色边框
$("#username").css("border", "1px solid yellow");
}
return flag;
}
5.2 mapper层
- UserMapper.java
src\main\java\com\ssmtravel\mapper\UserMapper.java
// 判断用户是否已经存在
@Select("select * from tab_user where username = #{username}")
Boolean findByUserName(String username);
// 保存用户
@Insert("insert into tab_user values()")
void saveUser(User user);
- UserMapper.xml
这时候即可创建 src\main\resources\com\ssmtravel\mapper\UserMapper.xml
<mapper namespace="com.ssmtravel.mapper.UserMapper">
<insert id="saveUser">
insert into tab_user (username, password, name, birthday, sex, telephone, email, status, code)
values (#{username},#{password},#{name},#{birthday},#{sex},#{telephone},#{email},#{status},#{code});
</insert>
</mapper>
5.3 service层
- 创建接口
UserService.jave
package com.ssmtravel.service;
import com.ssmtravel.domain.User;
public interface UserService {
// 判断用户是否已经存在
Boolean findByUserName(String username);
// 保存用户
void saveUser(User user);
}
- 创建实现 UserServiceImpl.java
package com.ssmtravel.service.Impl;
import com.ssmtravel.domain.User;
import com.ssmtravel.mapper.UserMapper;
import com.ssmtravel.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @title: UserServiceImpl
* @Author Qian
* @Date: 2022/4/14 16:00
* @Version 1.0
*/
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
public Boolean findByUserName(String username) {
Boolean aBoolean = userMapper.findByUserName(username);
return aBoolean;
}
public void saveUser(User user) {
userMapper.saveUser(user);
}
}
5.4 web层
package com.ssmtravel.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ssmtravel.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
/**
* @title: UserContorller
* @Author Qian
* @Date: 2022/4/14 16:09
* @Version 1.0
*/
@Controller
@RequestMapping("/user")
public class RegisterContorller {
private String err_msg = null;
@Autowired
private UserService userService;
// ******************************* 一.注册 ****************************************
@RequestMapping(value = "/selectByUserName",produces={"application/json; charset=UTF-8"})
@ResponseBody
public String selectByUserName(String username) throws IOException {
Boolean byUserName = userService.findByUserName(username);
if (byUserName != null) {
err_msg = "用户名已存在";
} else {
err_msg = "success";
}
ObjectMapper objectMapper = new ObjectMapper();
return valueAsString = objectMapper.writeValueAsString(err_msg);
}
}
通过jackson转换json格式字符串,回写字符串:
ObjectMapper objectMapper = new ObjectMapper();
String valueAsString = objectMapper.writeValueAsString(err_msg);
5.5 效果
6. 异步提交表单
采用异步提交表单
6.1 图片验证码
页面显示验证码,需要生成验证码,主要到有一个 src=“checkCode”,所以需要先创建一个工具类生成图片验证码,同时创建一个CkeckCodeController,同时存入session,当用户提交表单时,从session获取验证码和前端提交的验证码比较验证即可。
- CheckCodeUtils.java 工具类
网上搜索
package com.ssmtravel.utils;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class CheckCodeUtils {
public static final String RANDOMCODEKEY = "CHECKCODE_SERVER";//放到session中的key
private Random random = new Random();
private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生的字符串
private int width = 80;//图片宽
private int height = 26;//图片高
private int lineSize = 40;//干扰线数量
private int stringNum = 4;//随机产生字符数量
/**
* 生成随机图片
*/
public void getRandcode(HttpServletRequest request,
HttpServletResponse response) {
HttpSession session = request.getSession();
//BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
//产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
Graphics g = image.getGraphics();
g.fillRect(0, 0, width, height);
g.setFont(new Font("Times New Roman",Font.ROMAN_BASELINE,18));
g.setColor(getRandColor(160, 200));
//绘制干扰线
for(int i=0;i<=lineSize;i++){
drowLine(g);
}
//绘制随机字符
String randomString = "";
for(int i=1;i<=stringNum;i++){
randomString=drowString(g,randomString,i);
}
session.removeAttribute(RANDOMCODEKEY);
session.setAttribute(RANDOMCODEKEY, randomString);
g.dispose();
try {
//将内存中的图片通过流动形式输出到客户端
ImageIO.write(image, "JPEG", response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 获得字体
*/
private Font getFont(){
return new Font("Fixedsys",Font.CENTER_BASELINE,18);
}
/*
* 获得颜色
*/
private Color getRandColor(int fc,int bc){
if(fc > 255)
fc = 255;
if(bc > 255)
bc = 255;
int r = fc + random.nextInt(bc-fc-16);
int g = fc + random.nextInt(bc-fc-14);
int b = fc + random.nextInt(bc-fc-18);
return new Color(r,g,b);
}
/*
* 绘制字符串
*/
private String drowString(Graphics g,String randomString,int i){
g.setFont(getFont());
g.setColor(new Color(random.nextInt(101),random.nextInt(111),random.nextInt(121)));
String rand = String.valueOf(getRandomString(random.nextInt(randString.length())));
randomString +=rand;
g.translate(random.nextInt(3), random.nextInt(3));
g.drawString(rand, 13*i, 16);
return randomString;
}
/*
* 绘制干扰线
*/
private void drowLine(Graphics g){
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(13);
int yl = random.nextInt(15);
g.drawLine(x, y, x+xl, y+yl);
}
/*
* 获取随机的字符
*/
public String getRandomString(int num){
return String.valueOf(randString.charAt(num));
}
}
- CheckCodeController.java
新建CheckCodeController.java文件,主要控制验证码的生成及点击图片变换验证码
package com.ssmtravel.controller;
import com.ssmtravel.utils.CheckCodeUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 验证码
*/
@Controller
public class CheckCodeController {
/**
* 获取生成验证码显示到页面
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(value="/checkCode")
public void checkCode(HttpServletRequest request, HttpServletResponse response)
throws Exception {
//设置相应类型,告诉浏览器输出的内容为图片
response.setContentType("image/jpeg");
//设置响应头信息,告诉浏览器不要缓存此内容
response.setHeader("pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expire", 0);
CheckCodeUtils checkCodeUtils = new CheckCodeUtils();
try {
checkCodeUtils.getRandcode(request, response);//输出图片方法
} catch (Exception e) {
e.printStackTrace();
}
}
}
6.2 异步提交表单
// *********************************** 异步提交表单 *********************************
$(function(){
$(".submit").click(function () {
var options = {
type: "POST",
url:"/ssm-travel/user/addUser",
data:$("#registerForm").serialize(), // 序列化参数
dataType: "json",
error: function(request) {
return false;
},
success: function(data) {
if (data == "success"){
$("#errorMsg").css("visibility","hidden");
// 如果成功,则跳转注册成功页面
location.href = "/ssm-travel/register_ok.html";
}else {
$("#errorMsg").css("visibility","visible");
$("#errorMsg").html(data);
}
}
};
// 校验所有都为 true,则使用ajax提交表单
if (xiaoyan_password() && xiaoyan_email() &&
xiaoyan_name() && xiaoyan_telephone() && xiaoyan_birthday()){
$.ajax(options);
}
return false;
});
});
6.3 mapper层
src\main\java\com\ssmtravel\mapper\UserMapper.java
.........
.........
.........
// 激活邮箱,验证激活码code
Boolean updateStatus(String code);
这时候即可创建 src\main\resources\com\ssmtravel\mapper\UserMapper.xml
<update id="updateStatus">
update tab_user
set status = 'Y'
where code = #{code};
</update>
6.4 service层
- UserService.jave 接口
......
......
......
// 激活邮箱
Boolean activeUser(String code);
- UserServiceImpl.java 实现
@Override
public Boolean activeUser(String code) {
Boolean aBoolean = userMapper.updateStatus(code);
return aBoolean;
}
6.5 web层
// 1. 验证用户名是否存在
......
......
......
// 2. 验证通过 添加用户
@RequestMapping(value = "/addUser",produces={"application/json; charset=UTF-8"})
@ResponseBody
public String addUser(User user,HttpSession session,String check) throws IOException {
// 先校验验证码,验证码通过,则进行下面操作,不通过则失败
// 验证码
// 从session、中获取验证码
String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
// 为了保证验证码使用一次就重新生成
session.removeAttribute("CHECKCODE_SERVER");
if (checkcode_server == null || !checkcode_server.equalsIgnoreCase(check)) {
err_msg = "验证码有误";
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(err_msg);
}
user.setStatus("N");// 表示未激活
user.setCode(UuidUtil.getUuid()); // 生成激活码
userService.saveUser(user); // 添加用户
// 添加完成,发送邮件
String content = "<a href='http://localhost:8000/ssm-travel/user/activeUser?code=" + user.getCode() + "'>点击激活</a> ";
MailUtils.sendMail(user.getEmail(),content,"激活邮件");
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString("success");
}
// 3. 邮箱激活
@RequestMapping(value = "/activeUser")
@ResponseBody
public void activeUser(String code, HttpServletResponse response) throws IOException {
Boolean activeUser = userService.activeUser(code);
System.out.println(activeUser);
String msg = null;
if (activeUser){
//激活成功
msg = "<p>激活成功,请<a href='http://localhost:8000/ssm-travel/login.html'>登录</a><p>";
}else {
// 激活失败
msg = "激活失败,请联系管理员";
}
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print(msg);
}
1.需要使用 UuidUtil工具类生成激活码,同时发送邮件,邮件正文就是“点击激活”,当用户点击则会携带激活码访问:/activeUser,获取到激活码,与数据库查询激活码比较,正确则让用户跳转登录,否则激活失败。
2.用户初始激活状态为 “N”,当用户激活成功,改为“Y”。
3. 发送邮件,需要 使用 MailUtils工具类发送,需要邮箱名称和授权码才能发送,具体可在网上自行搜索。
到此,注册功能就完成了