文章目录

前言1、数据库准备2、工具类与相关基类使用2.1、工具类2.2、相关基类

3、web包目录说明4、注册功能设计(本文核心部分)4.1、注册页面设计4.2、注册逻辑设计

5、登陆功能设计5.1、登陆页面设计5.2、登陆逻辑设计

6、运行效果图

前言

大多数的网页都离不开注册登陆这两个功能,所以我想结合所学知识,使用vue.js、thymeleaf、Ajax做出一个简易通用的模板,该模板应具有如下功能:

用户名和密码是否按照一定格式输入提示用户名是否已存在两次输入密码是否一致密码进行md5加密处理验证码点击刷新符合条件的输入框显示对勾,否则提示具体错误信息只有全部显示正确才可以进行注册或者登陆

1、数据库准备

确保mysql正确安装配置,使用可视化工具如Navicat操作数据库,创建数据库名称如atweb,建立t_user表格,语句如下(新建查询后直接粘贴运行即可):

-- 创建数据库

create database atweb;

--创建表格

use atweb;

create table if not exists t_user

(

u_id int primary key auto_increment comment '主键且自增',

u_name varchar(40) not null,

u_pwd varchar(100) comment '考虑到加密,长度尽量多给',

u_describe varchar(50) comment '后续字段有需要自行添加'

)

成功创建的提示为:

2、工具类与相关基类使用

我们通常会把一些需要经常调用且很少变化的代码 封装 起来作为方法或者类,以提高开发效率和减少出错的可能行。

2.1、工具类

JDBCTools工具类:

主要用来读取数据库配置文件,具有连接数据库和释放连接的功能代码如下: package com.qb.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;

import java.sql.Connection;

import java.sql.SQLException;

import java.util.Properties;

public class JDBCTools {

// 1、创建数据源,即连接池

private static DataSource dataSource;

// 2、创建ThreadLocal对象

private static ThreadLocal threadLocal;

static {

try {

//1、读取druid.properties文件

Properties pro = new Properties();

pro.load(JDBCTools.class.getClassLoader().getResourceAsStream("druid.properties"));

//2、连接连接池

dataSource = DruidDataSourceFactory.createDataSource(pro);

//3、创建线程池

threadLocal = new ThreadLocal<>();

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 获取连接的方法

* 后续知识: 数据库事务操作 必须使用同一个数据库连接

* @return

* @throws SQLException

*/

public static Connection getConnection() {

// 从线程中获取连接 threadLocal可以保证线程安全

Connection connection = threadLocal.get();

if (connection == null) {

// 从连接池中获取一个连接

try {

connection = dataSource.getConnection();

// 将连接与当前线程绑定

threadLocal.set(connection);

} catch (SQLException e) {

e.printStackTrace();

}

}

return connection;

}

//释放连接的方法

public static void releaseConnection() {

// 获取当前线程中的连接

Connection connection = threadLocal.get();

if (connection != null) {

try {

connection.close();

// 将已经关闭的连接从当前线程中移除

threadLocal.remove();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

MD5Util工具类

针对明文字符串执行MD5加密代码如下: package com.qb.util;

import java.math.BigInteger;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

public class MD5Util {

public static String encode(String source) {

// 1.判断明文字符串是否有效

if (source == null || "".equals(source)) {

throw new RuntimeException("用于加密的明文不可为空");

}

// 2.声明算法名称

String algorithm = "md5";

// 3.获取MessageDigest对象

MessageDigest messageDigest = null;

try {

messageDigest = MessageDigest.getInstance(algorithm);

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

}

// 4.获取明文字符串对应的字节数组

byte[] input = source.getBytes();

// 5.执行加密

byte[] output = messageDigest.digest(input);

// 6.创建BigInteger对象

int signum = 1;

BigInteger bigInteger = new BigInteger(signum, output);

// 7.按照16进制将bigInteger的值转换为字符串

int radix = 16;

String encoded = bigInteger.toString(radix).toUpperCase();

return encoded;

}

}

ThreadLocalUtil工具类

代码如下: package com.qb.util;

public class ThreadLocalUtil {

//1.指定ThreadLocal对象

private static ThreadLocal threadLocal = new ThreadLocal<>();

public static void setStr(String name){

threadLocal.set(name);

//添加数据

}

public static String getStr(){

//获取数据

return threadLocal.get();

}

public static void remove(){

//移除数据

threadLocal.remove();

}

}

2.2、相关基类

BaseServlet类

该类继承HttpServlet类,封装模板引擎,方便跳转请求的编写封装doGet和doPost方法,可通过传递方法名称调用指定方法(利用反射)代码如下: public class BaseServlet extends HttpServlet {

private TemplateEngine templateEngine;

//使用模版引擎需要实例化模版引擎对象 并且设定前缀和后缀

@Override

public void init() throws ServletException {

// 1.获取ServletContext对象

ServletContext servletContext = this.getServletContext();

// 2.创建Thymeleaf解析器对象

ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

// 3.给解析器对象设置参数

// ①HTML是默认模式,明确设置是为了代码更容易理解

templateResolver.setTemplateMode(TemplateMode.HTML);

// ②设置前缀

String viewPrefix = servletContext.getInitParameter("view-prefix");

templateResolver.setPrefix(viewPrefix);

// ③设置后缀

String viewSuffix = servletContext.getInitParameter("view-suffix");

templateResolver.setSuffix(viewSuffix);

// ④设置缓存过期时间(毫秒)

templateResolver.setCacheTTLMs(60000L);

// ⑤设置是否缓存

templateResolver.setCacheable(true);

// ⑥设置服务器端编码方式

templateResolver.setCharacterEncoding("utf-8");

// 4.创建模板引擎对象

templateEngine = new TemplateEngine();

// 5.给模板引擎对象设置模板解析器

templateEngine.setTemplateResolver(templateResolver);

}

//使用模版引擎 转发到页面 并且渲染数据

protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {

// 1.设置响应体内容类型和字符集

resp.setContentType("text/html;charset=UTF-8");

// 2.创建WebContext对象

WebContext webContext = new WebContext(req, resp, getServletContext());

// 3.处理模板数据

templateEngine.process(templateName, webContext, resp.getWriter());

}

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

doPost(req,resp);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

req.setCharacterEncoding("utf-8");

resp.setContentType("text/html;charset=utf-8");

String methodName = req.getParameter("method");

try {

Method method = this.getClass().getDeclaredMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);

method.setAccessible(true);

method.invoke(this,req,resp);

} catch (Exception e) {

System.out.println("反射方法有误,请检查:"+methodName);

e.printStackTrace();

throw new RuntimeException(e);

}

}

}

BaseDaoImpl类

该类为数据库操作的基类封装了常用的数据库增删该查操作代码如下: public abstract class BaseDaoImpl {

private QueryRunner queryRunner = new QueryRunner();

/**

* 通用的增删改的方法

* @param sql String sql

* @param args Object... 如果sql中有?,就传入对应个数的?

* @return int 受影响行数

*/

protected int update(String sql,Object... args) {

try {

return queryRunner.update(JDBCTools.getConnection(),sql,args);

} catch (SQLException e) {

throw new RuntimeException(e);

}

}

/**

* 查询单个对象的方法

* @param clazz Class 记录对应的类类型

* @param sql String 查询语句

* @param args Object... 如果sql中有?,即根据条件查询

* @param 泛型方法声明的泛型类型

* @return T 一个对象

*/

protected T getBean(Class clazz, String sql, Object... args){

List list = getList(clazz, sql, args);

if(list != null && list.size()>0) {

//return getList(clazz, sql, args).get(0);

return list.get(0);

}

return null;

}

/**

* 通用查询多个对象的方法

* @param clazz Class 记录对应的类类型

* @param sql String 查询语句

* @param args Object... 如果sql中有?,即根据条件查询,可以设置?的值

* @param 泛型方法声明的泛型类型

* @return List 把多个对象放到了List集合

*/

protected List getList(Class clazz, String sql, Object... args){

try {

return queryRunner.query(JDBCTools.getConnection(),sql,new BeanListHandler(clazz),args);

} catch (SQLException e) {

throw new RuntimeException(e);

}

}

protected Object getValue(String sql,Object... args){

try {

return queryRunner.query(JDBCTools.getConnection(),sql,new ScalarHandler(),args);

} catch (SQLException e) {

throw new RuntimeException(e);

}

}

protected void batch(String sql,Object[][] args){

try {

queryRunner.batch(JDBCTools.getConnection(),sql,args);

} catch (SQLException e) {

throw new RuntimeException(e);

}

}

}

SysResult类

用于封装系统操作结果,并提供了一些静态工厂方法来方便创建不同类型的响应对象代码如下: package com.qb.vo;

import java.io.Serializable;

public class SysResult implements Serializable {

private Boolean flag;

private String msg;

private Object data;

public static SysResult success(String msg,Object data){

return new SysResult(true,msg,data);

}

public static SysResult success(Object data){

return new SysResult(true,"业务调用成功",data);

}

public static SysResult success(){

return new SysResult(true,"业务调用成功",null);

}

public static SysResult fail(){

return new SysResult(false,"业务调用失败",null);

}

public Boolean getFlag() {

return flag;

}

public void setFlag(Boolean flag) {

this.flag = flag;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

public Object getData() {

return data;

}

public void setData(Object data) {

this.data = data;

}

public SysResult() {}

public SysResult(Boolean flag, String msg, Object data) {

this.flag = flag;

this.msg = msg;

this.data = data;

}

}

3、web包目录说明

首先需要把所需的jar包引入到lib下,并执行Add as Library操作创建static包,并在里面创建script包,引入axios.js和vue.js脚本创建pages包和user包,新建注册和登陆的html网页配置web.xml文件(配置了验证码生成的servlet),内容如下:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"

version="4.0">

view-prefix

/WEB-INF/pages/

view-suffix

.html

KaptchaServlet

com.google.code.kaptcha.servlet.KaptchaServlet

KaptchaServlet

/kaptcha

4、注册功能设计(本文核心部分)

注意:位于WEB-INF下的页面不可以通过地址栏直接访问,只能通过服务器内部跳转,因此需要一个IndexServlet来访问首页,它的功能就是简单的跳转,代码如下:

@WebServlet("/index.html")

public class IndexServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

doPost(req,resp);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

req.getRequestDispatcher("/WEB-INF/pages/index.html").forward(req,resp);

}

}

首页的设计很简单,提供两个超链接,负责 前往注册 和 前往登陆,代码如下:

首页

前往注册

前往登陆

上面的 xmlns:th="http://www.thymeleaf.org"提供了thymeleaf模板引擎内容, 将路径提升到根部的url,因此下面的超链接可以不用写前缀

4.1、注册页面设计

由于页面代码片段切分起来麻烦,我会整体展示页面源代码,并在代码间做详细注释

页面源代码展示:

用户注册

//以下两行代码用来引入js脚本

// 这里的 app 将会在下面Vue对象的属性中进行绑定

// 每对tr标签代表一行数据,v-model用于属性绑定,会随着vue对象属性的改变而改变

// @blur代表离焦事件,也就是失去鼠标的光标后自动触发,属性和方法都在vue对象中定义

// 验证码生成是利用jar包里的servlet,而该servlet已在web.xml中配置

// changeImage用来点击刷新图片,具体逻辑见下面的注释

用户名
密码
确认密码
个人描述
验证码
html5 java 基于vue.js+thymeleaf模板引擎+ajax的注册登陆简洁模板(含从零到一详细介绍)  第1张

4.2、注册逻辑设计

下面是业务逻辑层源码与重要注释:

@WebServlet("/user")

public class UserServlet extends BaseServlet {

private final UserService us = new UserServiceImpl();

// 该实例化对象用于调用writeValueAsString方法将对象转化为json串

private final ObjectMapper MAPPER = new ObjectMapper();

// 跳转到注册页面

protected void toRegister(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

this.processTemplate("user/register", req, resp);

}

// 跳转到登陆页面

protected void toLogin(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

this.processTemplate("user/login", req, resp);

}

// 注册功能,添加user对象

protected void register(HttpServletRequest req, HttpServletResponse resp) throws Exception {

User user = new User();

// 这行代码可以接收前端传来的数据,并将其作为对象属性封装到对象中

// 但是需要注意,形参的键需要和类的属性名保持一致

BeanUtils.populate(user,req.getParameterMap());

// 调用service层的方法(三层大家都了解过吧,后续再调用dao层,不做解释)

us.registerByUser(user);

/* 下面代码不生效,使用axios进行处理

简单理解为:通过ajax发起请求,那么这次请求就不能再使用resp的重定向,而是

将重定向数据作为数据存入到响应体中,最后在axios里完成重定向跳转

resp.sendRedirect(req.getContextPath()+"/user?method=toLogin");*/

String realHref = req.getContextPath()+"/user?method=toLogin";

// 将路径存入到SysResult(响应体对象)

String json = MAPPER.writeValueAsString(SysResult.success(realHref));

// 将json数据返回到原请求

resp.getWriter().write(json);

}

// 检查用户名是否已存在

protected void checkNameUnique(HttpServletRequest req, HttpServletResponse resp) throws Exception {

String username = req.getParameter("username");

// System.out.println(username);

// 逻辑:通过查询数据库中该用户名的数量来判断用户是否存在

long res = us.selectUserByCount(username);

String json = "";

if (res > 0) {

// 数量大于零,用户已存在,响应fail方法

json = MAPPER.writeValueAsString(SysResult.fail());

} else {

// 不存在则响应success方法

json = MAPPER.writeValueAsString(SysResult.success());

}

resp.getWriter().write(json);

}

// 检查验证码是否正确,代码上面方法类似,不做解释

protected void checkCode(HttpServletRequest req, HttpServletResponse resp) throws Exception {

String code = req.getParameter("code");

// realCode存储在session中

String realCode = (String) req.getSession().getAttribute("KAPTCHA_SESSION_KEY");

String json = "";

if (code.equals(realCode)) {

json = MAPPER.writeValueAsString(SysResult.success());

} else {

json = MAPPER.writeValueAsString(SysResult.fail());

}

resp.getWriter().write(json);

}

}

5、登陆功能设计

登陆的功能与注册类似,比起注册,登陆的代码量要少很多,而且完全可以复用注册的代码。

5.1、登陆页面设计

源代码展示(相关解释会在注释中出现):

用户登陆

用户名
密码
验证码
html5 java 基于vue.js+thymeleaf模板引擎+ajax的注册登陆简洁模板(含从零到一详细介绍)  第2张

5.2、登陆逻辑设计

与注册逻辑设计相比,登陆只有下面这段代码是核心:

protected void login(HttpServletRequest req, HttpServletResponse resp) throws Exception {

User user_login = new User();

BeanUtils.populate(user_login,req.getParameterMap());

String json = "";

boolean flag = us.selectByUser(user_login);

if (flag) {

String realHref = req.getContextPath()+"/index.html";

json = MAPPER.writeValueAsString(SysResult.success(realHref));

}else{

json = MAPPER.writeValueAsString(SysResult.fail());

}

resp.getWriter().write(json);

}

这段代码的意思就是创建User对象并通过工具类给对象的账号和密码属性赋值,随后根据账号密码来查找数据库中是否存在账号密码对应的用户,若有就响应success和首页地址,若没有就响应fail,最后通过resp将json数据返回前端ajax。

6、运行效果图

首页 注册 正确输入后的注册 登陆 正确输入后的登陆

码文不易,如有帮助请留下免费的大拇指,想要源码的评论区留言即可,我会上传资源在本平台。

推荐链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。