基于vue.js+thymeleaf模板引擎+ajax的注册登陆简洁模板(含从零到一详细介绍)

文章目录

    • 前言
    • 1、数据库准备
    • 2、工具类与相关基类使用
      • 2.1、工具类
      • 2.2、相关基类
    • 3、web包目录说明
    • 4、注册功能设计(本文核心部分)
      • 4.1、注册页面设计
      • 4.2、注册逻辑设计
    • 5、登陆功能设计
      • 5.1、登陆页面设计
      • 5.2、登陆逻辑设计
    • 6、运行效果图

前言

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

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

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、工具类

  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<Connection> 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();}}}
    }
  2. 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;}}
    
  3. ThreadLocalUtil工具类

    • 代码如下:
    package com.qb.util;
    public class ThreadLocalUtil {//1.指定ThreadLocal对象private static ThreadLocal<String> 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、相关基类

  1. BaseServlet类

    • 该类继承HttpServlet类,封装模板引擎,方便跳转请求的编写
    • 封装doGetdoPost方法,可通过传递方法名称调用指定方法(利用反射
    • 代码如下:
    public class BaseServlet extends HttpServlet {private TemplateEngine templateEngine;//使用模版引擎需要实例化模版引擎对象  并且设定前缀和后缀@Overridepublic 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());}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected 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);}}
    }
  2. 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 <T> 泛型方法声明的泛型类型* @return  T 一个对象*/protected <T> T getBean(Class<T> clazz, String sql, Object... args){List<T> 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 <T> 泛型方法声明的泛型类型* @return List<T> 把多个对象放到了List集合*/protected <T> List<T> getList(Class<T> clazz, String sql, Object... args){try {return queryRunner.query(JDBCTools.getConnection(),sql,new BeanListHandler<T>(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);}}}
    
  3. 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包目录说明

在这里插入图片描述

  1. 首先需要把所需的jar包引入到lib下,并执行Add as Library操作
  2. 创建static包,并在里面创建script包,引入axios.jsvue.js脚本
  3. 创建pages包和user包,新建注册和登陆的html网页
  4. 配置web.xml文件(配置了验证码生成的servlet),内容如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"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"><context-param><param-name>view-prefix</param-name><param-value>/WEB-INF/pages/</param-value></context-param><context-param><param-name>view-suffix</param-name><param-value>.html</param-value></context-param><servlet><servlet-name>KaptchaServlet</servlet-name><servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class></servlet><servlet-mapping><servlet-name>KaptchaServlet</servlet-name><url-pattern>/kaptcha</url-pattern></servlet-mapping>
    </web-app>
    

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

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

@WebServlet("/index.html")
public class IndexServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.getRequestDispatcher("/WEB-INF/pages/index.html").forward(req,resp);}
}

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

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><base th:href="@{/}"><title>首页</title>
</head>
<body>
<a href="user?method=toRegister">前往注册</a>
<a href="user?method=toLogin">前往登陆</a>
</body>
</html>

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

4.1、注册页面设计

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

页面源代码展示:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><base th:href="@{/}"><title>用户注册</title>//以下两行代码用来引入js脚本<script src="static/script/vue.js"></script><script src="static/script/axios.js"></script>
</head>
<body>
// 这里的 app 将会在下面Vue对象的属性中进行绑定
<div id="app"><table border="1" cellspacing="0" cellpadding="0" align="center" width="48%">// 每对tr标签代表一行数据,v-model用于属性绑定,会随着vue对象属性的改变而改变// @blur代表离焦事件,也就是失去鼠标的光标后自动触发,属性和方法都在vue对象中定义<tr align="center"><td>用户名</td><td><input type="text" name="username" v-model="user.username" @blur="checkUsername"></td><td><span v-text="msg.usernameErrorMsg"></span></td></tr><tr align="center"><td>密码</td><td><input type="password" name="password" v-model="user.password" @blur="checkUserPwd"></td><td><span v-text="msg.passwordErrorMsg"></span></td></tr><tr align="center"><td>确认密码</td><td><input type="password" name="rePassword" v-model="user.rePassword" @blur="checkUserRePwd"></td><td><span v-text="msg.passwordErrorMsg2"> </span></td></tr><tr align="center"><td>个人描述</td><td><input type="text" name="describe" v-model="user.describe" @blur="checkDescription"></td><td><span v-text="msg.describeMsg"></span></td></tr><tr align="center"><td>验证码</td><td><input type="text" name="code" v-model="code" @blur="checkCode"></td><td><span v-text="msg.codeMsg"></span></td></tr>// 验证码生成是利用jar包里的servlet,而该servlet已在web.xml中配置// changeImage用来点击刷新图片,具体逻辑见下面的注释<tr><td colspan="3"><img :src="kaptchaImg" alt="" width="100px" height="50px" @click="changeImage"></td></tr><tr align="center"><td colspan="3"><button @click="register">注册</button></td></tr></table><script type="text/javascript">// vue对象const app = new Vue({el: "#app", // 绑定上面的div iddata: { // data代表属性,里面可以定义各种对象,并无限嵌套msg: {// 消息对象usernameErrorMsg: "用户名应为6~16位数字和字母组成",passwordErrorMsg: "密码的长度至少为8位",passwordErrorMsg2: "密码两次输入不一致",describeMsg:"请输入个人描述",codeMsg: "请输入正确的验证码"},// 全局变量,上面user.xx 就是和这里的user属性保持一致user: {username: '',password: '',rePassword:'',describe:'',},// 标志数组,只有用户输入数据全部正确,才会发起注册请求flagArray:[0,0,0,0,0],// 验证码code:'',// 表示生成验证码的servletkaptchaImg:"kaptcha"},methods: {// 异步请求,用来检查验证码是否输入正确,sysResult代表响应的对象,页面根据对象属性做不同操作async checkCode() {// axios.get这行代码,代表使用get请求,访问业务逻辑的user并携带method和code两个参数let {data:sysResult} = await axios.get("user?method=checkCode&code=" + this.code)if (sysResult.flag) {this.msg.codeMsg = "√"this.flagArray[4] = 1}else{this.msg.codeMsg = "请输入正确的验证码!"this.flagArray[4] = 0}},// 异步请求,用来规定用户名形式和检查用户名是否已存在async checkUsername() {// 正则表达式:用户名应为6~16个字母或数字组成let usernameRege = /^[a-zA-Z0-9]{6,16}$/let usernameFlag = usernameRege.test(this.user.username)// 符合用户名正则的继续判断用户是否已存在,否则直接提示用户名格式错误的信息if (usernameFlag) {// 这里同上,使用get请求,访问user并携带两个参数,根据响应对象属性做出特定操作let {data:sysResult} = await axios.get("user?method=checkNameUnique&username="+this.user.username)if (sysResult.flag) {this.msg.usernameErrorMsg = "√"this.flagArray[0] = 1}else{this.msg.usernameErrorMsg = "用户名已存在!"this.flagArray[0] = 0}}else{this.msg.usernameErrorMsg = "用户名应为6~16位数字和字母组成"this.flagArray[0] = 0}},// 正则判断用户密码是否符合要求checkUserPwd() {// 描述至少为8个字符let pwdRege = /^.{8,}$/let pwdFlag = pwdRege.test(this.user.password)if(pwdFlag){this.msg.passwordErrorMsg = "√"this.flagArray[1] = 1}else{this.msg.passwordErrorMsg = "密码的长度至少为8位"this.flagArray[1] = 0}},// 判断两次密码输入是否一致,注意判断使用三个连续等号checkUserRePwd() {if (this.user.password === this.user.rePassword) {this.msg.passwordErrorMsg2 = "√"this.flagArray[2] = 1}else{this.msg.passwordErrorMsg2="两次输入的密码不一致!"this.flagArray[2] = 0}},checkDescription() {// 描述至少为两个字符let desRege = /^.{2,}$/let desFlag = desRege.test(this.user.describe)if (desFlag) {this.msg.describeMsg = "√";this.flagArray[3] = 1} else {this.msg.describeMsg = "请输入个人描述"this.flagArray[3] = 0}},// 数组.join(",")可以将数组转化为字符串,元素使用逗号拼接async register() {if (this.flagArray.join(",") === "1,1,1,1,1") {alert("表单校验成功!")let p = this.user// 这里将页面输入的数据全部以参数的形式传递到业务逻辑层let {data:sysResult} = await axios.get(`user?method=register&uName=${p.username}&uPwd=${p.password}&uDescribe=${p.describe}`)if(sysResult.flag){// 注册成功应往登陆页面跳转,因此data属性保存的是重定向前往登陆的重定向路径window.location.href = sysResult.data}}else{// 阻止跳转event.preventDefault();alert("表单校验不成功!!!");}},// 验证码图片的刷新逻辑,只需要改变kaptcha方法的参数即可,这样浏览器检测到变化后,重新发起请求,从而改变验证码图片changeImage() {//浏览器解析到src的属性变化 则会重新发起请求,new Date充当随机数的作用this.kaptchaImg="kaptcha?date="+new Date()},}})</script>
</div>
</body>
</html>

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、登陆页面设计

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

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><base th:href="@{/}"><title>用户登陆</title><script src="static/script/vue.js"></script><script src="static/script/axios.js"></script>
</head>
<body>
<div id="app"><table border="1" cellspacing="0" cellpadding="0" align="center" width="48%"><tr align="center"><td>用户名</td><td><input type="text" name="username" v-model="user.username" @blur="checkUsername"></td><td><span v-text="msg.usernameMsg"></span></td></tr><tr align="center"><td>密码</td><td><input type="password" name="password" v-model="user.password" @blur="checkPwd"></td><td><span v-text="msg.passwordMsg"></span></td></tr><tr align="center"><td>验证码</td><td><input type="text" name="code" v-model="user.code" @blur="checkCode"></td><td><span v-text="msg.verifyMsg"></span></td></tr><tr><td colspan="3"><img :src="kapImg" alt="" width="100px" height="50px" @click="changeImg"></td></tr><tr align="center"><td colspan="3"><button @click="login">登陆</button></td></tr></table><script type="text/javascript">const app = new Vue({el: "#app",data: {msg: {usernameMsg: "请输入用户名",passwordMsg: "请输入密码",verifyMsg: "请输入验证码"},// 全局变量user: {username: '',password: '',code:''},flagArray:[0,0,0],kapImg:"kaptcha"},methods: {changeImg() {this.kapImg="kaptcha?date=" + new Date()},async checkCode() {let {data:sysResult} = await axios.get("user?method=checkCode&code=" + this.user.code)if (sysResult.flag) {this.msg.verifyMsg = "√"this.flagArray[2] = 1}else{this.msg.verifyMsg = "请输入正确的验证码!"this.flagArray[2] = 0}},async checkUsername() {// 用户名应为6~16个字母或数字组成let usernameRege = /^[a-zA-Z0-9]{6,16}$/let usernameFlag = usernameRege.test(this.user.username)if (usernameFlag) {this.msg.usernameMsg = "√"this.flagArray[0] = 1}else{this.msg.usernameMsg = "用户名格式错误,请根据注册账号进行输入"this.flagArray[0] = 0}},checkPwd() {let pwdRege = /^.{8,}$/let pwdFlag = pwdRege.test(this.user.password)if(pwdFlag){this.msg.passwordMsg = "√"this.flagArray[1] = 1}else{this.msg.passwordMsg = "密码的长度至少为8位"this.flagArray[1] = 0}},// 异步请求登陆,传递账号密码两个参数async login() {if (this.flagArray.join(",") === "1,1,1") {let p = this.userlet {data:sysResult} = await axios.get(`user?method=login&uName=${p.username}&uPwd=${p.password}`)if(sysResult.flag){alert("表单校验成功!")// 这里的data是首页地址,逻辑就是登陆成功跳转首页window.location.href = sysResult.data}else{alert("用户名或密码错误")event.preventDefault()}}else{// 阻止跳转event.preventDefault()alert("表单校验不成功!!!")}}}})</script>
</div>
</body>
</html>

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、运行效果图

  1. 首页
    在这里插入图片描述

  2. 注册
    在这里插入图片描述

  3. 正确输入后的注册
    在这里插入图片描述

  4. 登陆
    在这里插入图片描述

  5. 正确输入后的登陆
    在这里插入图片描述


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3016609.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

.双链表.

题目&#xff1a; 实现一个双链表&#xff0c;双链表初始为空&#xff0c;支持 55 种操作&#xff1a; 在最左侧插入一个数&#xff1b;在最右侧插入一个数&#xff1b;将第 k&#x1d458; 个插入的数删除&#xff1b;在第 k&#x1d458; 个插入的数左侧插入一个数&#xf…

四川景源畅信:抖音的运营策略有哪些?

在数字营销的大潮中&#xff0c;抖音以其巨大的用户基础和强大的传播力成为众多品牌和商家的必争之地。那么&#xff0c;抖音的运营策略有哪些呢?这个问题涉及到内容创作、用户互动、数据分析和品牌合作等多个方面。 一、内容创作与优化在抖音&#xff0c;内容是吸引用户的关键…

【牛客】[HNOI2003]激光炸弹

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 二维前缀和板题。 注意从&#xff08;1,1&#xff09;开始存即可&#xff0c;所以每次输入x,y之后&#xff0c;要x,y。 因为m的范围最大为…

python实验三 实现UDP协议、TCP协议进行服务器端与客户端的交互

实验三 实验题目 1、请利用生成器构造一下求阶乘的函数Factorial()&#xff0c;定义一个函数m()&#xff0c;在m()中调用生成器Factorial()生成小于100的阶乘序列存入集合s中&#xff0c;输出s。 【代码】 def factorial():n1f1while 1:​ f * n​ yield (f)​ n1…

栈的实现以及c语言解决括号匹配问题

一、栈的实现 1、头文件 typedef int STDataType; typedef struct Stack {STDataType* _a;int _top; // 栈顶int _capacity; // 容量 }Stack; // 初始化栈 void StackInit(Stack* ps); // 入栈 void StackPush(Stack* ps, STDataType data); // 出栈 void StackPop(S…

上位机图像处理和嵌入式模块部署(树莓派4b镜像烧录经验总结)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 陆陆续续也烧录了好多次树莓派的镜像了&#xff0c;这里面有的时候很快&#xff0c;有的时候很慢。特别是烧录慢的时候&#xff0c;也不知道是自己…

Partisia Blockchain 生态首个zk跨链DEX现已上线

在5月1日&#xff0c;由Partisia Blockchain与zkCross创建合作推出的Partisia zkCrossDEX在Partisia Blockchain生态正式上线。Partisia zkCrossDEX是Partisia Blockchain上重要的互操作枢纽&#xff0c;其融合了zkCross的zk技术跨链互操作方案&#xff0c;并利用Partisia Bloc…

Python批量计算多张遥感影像的NDVI

本文介绍基于Python中的gdal模块&#xff0c;批量基于大量多波段遥感影像文件&#xff0c;计算其每1景图像各自的NDVI数值&#xff0c;并将多景结果依次保存为栅格文件的方法。 如下图所示&#xff0c;现在有大量.tif格式的遥感影像文件&#xff0c;其中均含有红光波段与近红外…

pytest教程-39-钩子函数-pytest_runtest_setup

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest_runtest_protocol钩子函数的使用方法&#xff0c;本小节我们讲解一下pytest_runtest_setup钩子函数的使用方法。 pytest_runtest_setup 钩子函数在每个测试用例的 setup 阶段被调用。这…

代码随想录算法训练营DAY44|C++动态规划Part6|完全背包理论基础、518.零钱兑换II、377. 组合总和 Ⅳ

文章目录 完全背包理论基础完全背包问题的定义与01背包的核心区别为什么完全背包的循环顺序可以互换&#xff1f;CPP代码 ⭐️518.零钱兑换II思路CPP代码 ⭐️377. 组合总和 Ⅳ思路CPP代码 扩展题 完全背包理论基础 卡码网第52题 文章链接&#xff1a;完全背包理论基础 视频链接…

练习题(2024/5/7)

1验证二叉搜索树 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左 子树 只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 示例 …

互联网十万个为什么之什么是云计算

云计算是一种通过互联网提供计算资源和服务的技术。它允许用户随时随地访问和使用云平台上的数据、软件和硬件资源。在数字化时代&#xff0c;互联网已经成为基础设施。云计算使得数据中心能够像一台计算机一样去工作。通过互联网将算力以按需使用、按量付费的形式提供给用户&a…

城市二手房数据分析与房价预测

实现功能 数据分析 二手房价格-时间分析 二手房数量-时间分析 二手房分布-区域分析 二手房户型分析 二手房朝向分析 二手房价格-区域分析 二手房热词词云 房价预测 采用合适的算法模型&#xff0c;对模型进行评估。通过输入影响因素输出预测价格。 采用技术与框架 M…

【MM32F3270 Micropython】pwm输出

文章目录 前言一、PWM脉宽调制技术介绍二、machine.PWM 类2.1 machine.PWM 类的构造对象2.2 PWM 对象初始化2.3 关闭PWM设备2.4 设置pwm的周期2.5 设置占空比 三、pwm示例代码总结 前言 MicroPython是一种精简的Python 3编程语言实现&#xff0c;旨在在微控制器和嵌入式系统上…

从0到1提审苹果商店(appstore)上线一款新APP

本篇主要复盘和介绍一款APP如何从0到1上线到苹果商店,将我自己项目遇到的坑跟大家分享,希望能为同样做开发或者运营的你提供经验,少走弯路。 如果你是24年1月1日之后开始首次提审APP,还需要先将自己的APP在工信部备案,苹果后台增加了工信部备案号的填写,备案方法和经验如…

揭秘 IEEE/ACM Trans/CCF/SCI,谁才是科研界的王者?

会议之眼 快讯 在学术探索的浩瀚星海中&#xff0c;每一篇论文都像是一颗璀璨的星辰&#xff0c;而那些被顶级期刊或会议收录的论文&#xff0c;则无疑是最耀眼的几颗。 在众多评价标准中&#xff0c;IEEE/ACM Transactions、CCF推荐期刊和会议、SCI分区期刊&#xff0c;它们…

18 内核开发-内核重点数据结构学习

课程简介&#xff1a; Linux内核开发入门是一门旨在帮助学习者从最基本的知识开始学习Linux内核开发的入门课程。该课程旨在为对Linux内核开发感兴趣的初学者提供一个扎实的基础&#xff0c;让他们能够理解和参与到Linux内核的开发过程中。 课程特点&#xff1a; 1. 入门级别&…

Qt---day2-信号与槽

1、思维导图 2、 拖拽式 源文件 #include "mywidget.h" #include "ui_mywidget.h" MyWidget::MyWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::MyWidget) { ui->setupUi(this); //按钮2 this->btn2new QPushButton("按钮2",th…

什么是多模态大模型,有了大模型,为什么还要多模态大模型?

随着人工智能技术的愈演愈烈&#xff0c;其技术可以说是日新月异&#xff0c;每隔一段时间就会有新的技术和理念被创造出来&#xff1b;而多模态大模型也是其中之一。 什么是多模态 想弄明白什么是多模态大模型&#xff0c;那么首先就要弄明白什么是多模态。 简单来说&#x…

【Git】Commit后进行事务回滚

起因 因为一直使用git add .&#xff0c;在学习pytorch中添加了一个较大的数据集后&#xff0c;导致git push失败&#xff0c;而这个大数据集并不是必须要上传到仓库的&#xff0c;但是因为自己在设置.gitignore前已经进行了git comit&#xff0c;所以&#xff0c;需要进行事务…