html登录功能制作笔记(JavaWeb)

html登录功能制作笔记(JavaWeb)

光电大三学生一枚,对编程感兴趣。以下是在通过网上教学视频及各种资料,学习制作html登录功能时做的笔记,包含了制作过程中遇到的一些问题。

该简易项目是基于html,Java开发,采用Visual Studio和eclipse作为IDE。其中Visual Studio用于编写html代码负责网页部分制作,eclipse用于编写Java代码负责服务端的制作,MySQL作为数据库存放用户信息。
javaweb流程示意图

客户端HTML

< form >可为输入的用户名密码创建html表单

表单可包含input元素(文本字段,复选框,单选框,提交按钮等)等元素,可以向服务器传输数据

< table >定义html表格(通常为table元素+tr/th/td元素) 定义表格中的行 表头单元格(表头信息) 标准单元格(数据)

服务端JavaWeb

Servlet获取用户数据流程示意图
Servlet获取用户数据流程示意图

所需环境

Tomcat(Apache):应用最广泛的JavaWeb服务器

需要环境:

配置jdk环境变量:在此电脑–属性–高级系统设置–高级–环境变量 中找到系统环境变量一栏,新建一个变量名为JAVA_HOME 变量值为 jdk安装目录 的系统变量

环境配置完成后,打开tomcat/bin/startup.bat,正常启动说明环境配置成功,之后通过默认端口号localhost:8080(MySQL端口号3306)可访问tomcat服务器

以上配置完毕后,点击执行startup.bat可以执行,但是确无法访问localhost:8080,阅读tomcat字符界面,发现以下报错

15-Feb-2021 16:10:02.708 严重 [main] org.apache.catalina.util.LifecycleBase.handleSubClassException 初始化组件[Connector[HTTP/1.1-8080]]失败。

网上给出的报错原因:1.已经运行了一个tomcat 2.8080端口号被其他程序占用

cmd输入netstat -ano | findstr “8080” 查到是一进程号PID为9140的applicationwebserver.exe占用了8080端口,去任务管理器关闭后,访问localhost:8080可跳转至tomcat主页

为防止之后的冲突,将tomcat端口改为8888

IDEA配置tomcat时遇到的问题(在已经完成了tomcat_home等环境的前提下)

  • 配置方法1: 打开 Run – Edit Configurations,找到并添加Tomcat Server
    遇到问题:没有Tomcat Server,

  • 配置方法2:没有Tomcat Server选项的情况说明缺 tomcat 插件,依次打开 File / Settings / Plugins,搜索 tomcat 插件,找到 Tomcat and TomEE并安装
    遇到问题:无法查找到Tomcat and TomEE 插件

    查找总结:免费版本Community不支持Application Servers也不支持Tomcat

Eclipse配置方法

help-Install New Software 打开后,在Work with一栏中输入:2020-12 - http://download.eclipse.org/releases/2020-12(2020-12为Eclipse对应版本号),之后选择Web,XML,Java EE的一栏可安装插件

为了省事,直接重新下载了Eclipse for JavaEE,但打开时碰到了报错

Eclipse启动错误:A Java Runtime Environment(JRE) or Java Development Kit(JDK) must be available...

大意是我没有配置JDK环境…

解决方法打开Eclipse根目录eclipse.ini文件,在最前面加上两行:

-vm
C:\ProgramFiles\Java\jdk1.8.0_45\bin\javaw.exe

之后可以正常使用(Eclipse还需要配置tomcat才能使用server,但比较简单)

Servlet

sun公司制定的技术标准,包含与Web应用相关的一系列接口,即Web应用实现的宏观解决方案,具体的实现由Serviet容器负责实现(如tomcat),主要用于处理客户端请求

遇到问题:import javax.servlet.http.HttpServlet; 出现The import javax.servlet can’t be resolved报错,检查发现工程关联的tomcat9其中找不到相关的jar文件

解决方法:手动找到 Java Build Path -> Libraries -> Add External JARs…; 找到tomcat目录下的 servlet-api.jar添加

开发规则:通过继承HttpServlet来实现Servlet的开发

常用方法:doGet:处理客户端get方式请求

doPost:处理客户端post方式请求

service:根据具休的请求方式去调用对应的doGet,doPost方法(可以为了省事而直接重写service方法)

后端部分1.web.xml文件

功能:将客户端的请求进行匹配

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <!-- 配置LoginServlet 与处理请求的映射 -->
  <servlet>
  	<servlet-name>loginservlet</servlet-name><!-- <servlet>的<servlet-name>需与<servlet-mapping>中的<servlet-name>相同才能匹配,匹配成功后可跳转至相应的类中 -->
  	<servlet-class>Webtest_login.LoginServiet</servlet-class><!-- copy qualified name全类名 -->
  </servlet>
  <servlet-mapping>
  	<servlet-name>loginservlet</servlet-name>
  	<!-- 客户端登录请求:http://localhost:8888/Webtest01/login -->
  	<url-pattern>/login</url-pattern>
  </servlet-mapping>
</web-app>
客户端请求匹配过程:

与< servlet-mapping >中的< url-pattern >进行匹配, 匹配到以后。 再取< serv1et-mapping >
中的< servlet-name >,到< servlet >节点中匹配相同的< servlet- name > ,进而找到对应的< servlet-class >

然后Tomcat通过反射的方式创建LoginServlet的实例,很据具体的请求方式调用对应的doGet或者是doPost方法.

写基本连接代码时遇到了一些小问题,忽略了super关键字(super类似于this,用于访问/引用当期类或其父类的成员/方法)

	@Override
	protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException{
		super.doPost(req, resp);/*本意是要将客户端Get的请求转到doPost处理*/
	}

http://localhost:8888/Webtest01/login 访问/login时,浏览器报错:405 此URL不支持Http方法POST

解决方法:去掉doPost前的super

后端部分2. xxxServlet.java文件

功能:处理客户端请求(如登录验证,注册)

处理请求req(参数类型:HttpServletRequest)

返回响应resp(参数类型:HttpServletResponse)

获取请求参数值HttpServletRequest

:是ServletRequest接口的子接口,封装了HTTP请求的相关信息,由Servlet容器创建其实现类对象并传入service(ServletRequest reg, ServletResponse res)方法中。 (以下我们所说的HttpServletRequest 对象指的是容器提供的HttpServletReguest实现类对象)
主要功能:
1.获取请求参数
2.在请求域中绑定数据
3.将请求转发给另外一个URL地址(转发

转发

转发

(客户端发送一次请求)

if(userinfor==null)
		{
			//转发前绑定数据(交给下一个组建处理的数据,绑定到request对象中)
			req.setAttribute("login_msg", "用户名或密码错误");//错误提示
			req.setAttribute("loginuser_msg",username);//用户名
			//获取转发器
			RequestDispatcher rd = req.getRequestDispatcher("LoginTest.jsp");
			//开始转发
			rd.forward(req, resp);//把req和resp传给jsp
		}
获取请求参数值HttpServletResponse:

是ServletResponse接口的子接口,封装了HTTP响应的相关信息,由Servlet容器创建其实现类对象并传入service(ServletRequest reg, ServletResponse res)方法中。 (以下我们所说的HttpServletResponse对象指的是容器提供的HttpServletReguest实现类对象)
主要功能:
1.用PrintWriter向浏览器(客户端)发送数据
3.实现请求的重定向(重定向

重定向

重定向

(客户端发送两次请求)

if(userinfor==null)//用户名或密码不正确
		{
			//通过 重定向 方法重新发送登录页面
			//服务器给浏览器发送302状态码及一个新地址
			resp.sendRedirect("Html_LoginTest.html");
		}
源码部分

LoginServlet.java

package Webtest_login;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import Webtest_beans.UserInfor;
import Webtest_DAO.UserDAO_impl;
/*处理登录请求的Servlet*/
public class LoginServiet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	@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{
		System.out.println("login Request recived");
		/*HttpServletRequest:请求对象 Servlet容器收到请求后,创建一req对象,将Http请求相关信息全部封装到对象中*/
		req.setCharacterEncoding("UTF-8");
		//获取用户名
		String username = req.getParameter("username");
		String password = req.getParameter("password");
		System.out.println("用户名:"+username+"密码:"+password);
		//登录验证
		//通过resp响应给客户端数据
		resp.setContentType("text/html;charset=UTF-8");//text/html:文本格式  设置编码格式(必须在获取流之前设置,才能防止乱码)
		PrintWriter out = resp.getWriter();
		UserDAO_impl userdao = new UserDAO_impl();
		UserInfor userinfor = userdao.getUser(username, password);//java.lang.NullPointerException
		if(userinfor==null)
		{
			//转发前绑定数据(交给下一个组建处理的数据,绑定到request对象中)
			req.setAttribute("login_msg", "用户名或密码错误");//错误提示
			req.setAttribute("loginuser_msg",username);//用户名
			//获取转发器
			RequestDispatcher rd = req.getRequestDispatcher("LoginTest.jsp");
			//开始转发
			rd.forward(req, resp);//把req和resp传给jsp
		}else
		{
			out.println("<h1>登陆成功!</h1>");//打印在网页
		}
        
	}
}

文件示意图

后端部分3.用户数据库

该部分主要作用是将Sevlet处接收到的请求提取用户名及密码,并与MySQL建立连接,发送数据库查询语句。

所需文件:

mysql-connector-java-8.0.23.jar文件:处理mysql与java连接,放置于工程的 WebContent / WEB-INF / lib /目录下

UserInfor类

UserInfor.java(用于存放用户相关信息)

package Webtest_beans;

public class UserInfor {
	private Integer id;
	private String username;
	private String password;
    //以及id username password的getter()和setter()方法
    //重写 toString()方法
}
UserDAO类

用于实现与MySQL连接(具体的连接方法在ConnectionUtil中),并向其发送SQL语句+接收其返回的用户查询结果,最终返回一个UserInfor类。

UserDAO.java 为interface接口类

package Webtest_DAO;

import Webtest_beans.UserInfor;

public interface UserDAO {
	public UserInfor getUser(String name,String pwd);
}

UserDAO.impl.java 为UserDAO接口 中方法的具体实现

package Webtest_DAO;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import Webtest_Utils.ConnectionUtils;
import Webtest_beans.UserInfor;

public class UserDAO_impl implements UserDAO{

	@Override
	public UserInfor getUser(String name, String pwd) {
		UserInfor userInfortem = null;
		// 1. JDBC 获取连接
		try {
			/*链接数据库的具体信息 ,通过DriverManager.getConnection实现
			 * 现在已改为使用Connection类实现
			 * Class.forName("com.mysql.cj.jdbc.Driver");
			String url = "jdbc:mysql://localhost:3306/gwp_userinfor";
			String user="root";
			String pawd="123456";
			Connection conn = DriverManager.getConnection(url,user,pawd);
			*/
		// 2. 接收ConnectionUtils.getConn()返回与给定的字符串名称相关联类或接口的Class对象
			Connection conn = ConnectionUtils.getConn();
		// 3. 编写SQL
			String select_sql="select id,username,password from user_test where username = ? and password = ?";
			PreparedStatement ps = conn.prepareStatement(select_sql);//PreparedStatement 实例包含已编译的 SQL 语句
			ps.setString(1, name);//(parameterIndex, x) 执行 PreparedStatement 对象之前,必须设置每个 ? 参数的值
			ps.setString(2, pwd);
			//为防止用户在参数中输入非法值(如sql语句delete from tableName) 应使用prepareStatement代替Statement
		// 4. 执行SQL 并接收返回值
			ResultSet re = ps.executeQuery();
		// 5. 封装返回结果
			if(re.next())
			{
				System.out.println("用户"+re.getString("username")+"验证成功,密码"+re.getString("password"));
				userInfortem = new UserInfor();
				userInfortem.setId(re.getInt("id"));
				userInfortem.setUsername(re.getString("username"));
				userInfortem.setPassword(re.getString("password"));
				
				//return userInfortem;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			try {
		// 6. 关闭连接
				ConnectionUtils.closeConn();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return userInfortem;
	}

}
ConnectionUtils类

ConnectionUtils.java 通过db.properties文件中的信息。其getConn()方法可以查找到对应的数据库文件获取连接,最终返回一个Connection连接类。 其closeConn()方法可关闭连接

package Webtest_Utils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;


//连接工具类
public class ConnectionUtils {
	//静态代码块读取db.properties
	private static String driver=null;
	private static String url=null;
	private static String username=null;
	private static String password=null;
	private static Properties props = new Properties();
	
	//ThreadLocal:保证一个线程只有一个连接  防止单个客户端重复连接占用新线程
	private static ThreadLocal<Connection>tl=new ThreadLocal<>();
	//                          管理对象
	//文件读取
	static {//静态代码块--只执行一次
		try{
			//类加载器读取文件
			InputStream in = ConnectionUtils.class.getClassLoader().getResourceAsStream("db.properties");//返回文件的Stream
			props.load(in);//stream放入Properties
			
			driver = props.getProperty("jdbc.driver");
			url = props.getProperty("jdbc.url");
			username = props.getProperty("jdbc.username");
			password = props.getProperty("jdbc.password");
			System.out.println("driver="+driver);
			System.out.println("url="+url);
			Class.forName(driver);//类加载
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	//获取连接
	public static Connection getConn() throws Exception{
		//尝试从TreadLocal获取连接
		Connection conn = tl.get();
		if(conn==null)//若连接不存在,则新建连接
		{
			conn = DriverManager.getConnection(url,username,password);//建立新连接
			tl.set(conn);//新连接放入TreadLocal
		}
		return conn;//若连接存在,则返回原来的连接
	}
	
	//关闭连接
	public static void closeConn() throws Exception
	{
		//尝试从TreadLocal获取连接
		Connection conn=tl.get();
		if(conn!=null)
		{
			conn.close();
		}
		tl.set(null);//TreadLocal置为空,方便下次获取时建立新连接
	}
	
	//测试main
	public static void main(String[] args) throws Exception
	{
		Connection conn1=getConn();
		//closeConn();
		Connection conn2=getConn();
		System.out.println(conn1==conn2);//同客户端两次请求conn一定相等
	}
}

报错:客户端登录请求发送给服务端后,服务端提示语句

报错:Loading class `com.myspingxiecuowql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.		

(大意说不支持`com.mysql.jdbc.Driver,新的class叫com.mysql.cj.jdbc.Driver,原因和驱动依赖版本相关)

解决方法:修改为Class.forName(“com.mysql.cj.jdbc.Driver”)可解决

报错:服务器连接数据库出错:

java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/

可能错误:1.url格式不对

2.driver字符串出错

3.ClassPath没有加入合适的mysql_jdbc驱动

单独运行ConnectonUtils.java发现Class.forName(driver);//有java.lang.NullPointerException空指针错误,打印getProperty()方式获取的driver,发现为null,检查db.propertise发现系driver一栏拼写错误,修改后可正常连接

后端部分4.JSP页面(Java Server Page)

运行在java服务器中的页面(JavaWeb中的动态页面,本质是Servlet)

.jsp文件:HTML代码+Java代码+JSP标签 (执行后会自动生成.java文件 再编译成.class文件)

JSP擅长处理页面显示,Servlet擅长处理业务逻辑

jsp页面执行原理:

​ 本质为Servlet,执行时先转化为.java文件,再编译成.class文件
​ 将java代码直接放入java片段
​ html css js表达式通过输出流out.writer()方法显示

作用:

1.可以自动将html相关代码通过流写道浏览器端

2.支持写java代码,可以灵活地做出一些处理

请求转发:Servlet接收到浏览器请求后,先不响应,而是在服务器内转发给其他Servlet程序进行处理,这种情况下浏览器地址栏不会发生变化

(如,客户端发送请求–>Servlet处理业务,并转发结果–>jsp接收并处理网页显示部分–>返回给客户端

转发

缺点: 增加了产品复杂性

​ Java的运行速度是用class常驻内存来完成的,故"性价比"低

JSP隐含(内置)对象

out (jspWriter):相当于response.getWriterO获取的对象,用于在页面中显示信息
config (ServletConfg):对应Servlet中的ServletConfg对象
page (Object):对应当前Servlet对象,实际上就是this
pageContext (PageContext):当前页面的上下文,也是一个域对象
exception ( Throwable):错误页面中异常对象
request ( HttpServletReguest):HttpServletReguest 对象
response ( HttpServletResponse):HttpServletResponse 对象
application ( ServletContext):ServletContext 对象
session ( HttpSession):HttpSession对象

EL表达式(jsp内置表达式语言)

可访问页面上下文及不同作用域中的对象取得对象属性的值,或执行简单的运算/判断操作(EL可自动进行数据类型转换)

可代替jsp表达式中<%= %>输出操作(数据为null时,jsp表达式输出null,EL表达式中则不会输出)

语法:${ EL表达式 }

EL取值的四个域 (由小到大)

1.PageScope页面上下文
2.requestScope请求
3.sessionScope会话
4.applicationScope整个web应用

源码部分

LoginTest.jsp (放置于 项目/ WebContent 文件夹中)

其html部分的代码复制于原本的Login.html文件中,java部分的代码(<%-- --%> 或 <%= %>)用于动态更新并显示页面中的参数

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
    <meta charset="UTF-8"><!-- 使浏览器使用UTF-8编码 -->
    <title>用户登录</title>
    <script>
    	function clear_login_msg(){
    		var spanElement = window.document.getElementById("span_login_msg");
    		spanElement.innerHTML = "";//span内字符串
    	}
    </script>
</head>
<body><!-- action:请求的地址login相对路径
		method:请求的方式
		GET提交(不安全/提交大小有限制):localhost:8888/Webtest01/login?submit=login&user=admin&pwd=123
		POST(表单存放在请求体里/不暴露数据):localhost:8888/Webtest01/login		
 -->
    <form action="login" method="post" name="loginform" onsubmit="return Checked();">
		<table>
            <tr>
                <td>用户名</td>
                <td>
                	<%-- //java代码部分
                	<%
                    //获取request对象:request可直接使用
                    String LoginMsg = (String)request.getAttribute("login_msg");
                	String LoginUser = (String)request.getAttribute("loginuser_msg");
                    %>
                    --%>
                    <input type="text" placeholder="输入用户名" maxlength="8" name="username" value=${requestScope.loginuser_msg}<%--<%=LoginUser==null?"":LoginUser %>--%> οnfοcus="clear_login_msg()">
                    <%--<span style="color:red"><%=LoginMsg==null?"":LoginMsg %></span>--%>
            	<!-- <%=LoginMsg==null?"":LoginMsg %> 表示LoginMsg为空时输出空,否则直接输出值-->
                    <!-- EL默认从1.PageScope requestScope sessionScope applicationScope 中查找数据-->
                    <span id="span_login_msg">${requestScope.login_msg}</span>
                </td>
            </tr>
            <tr>
                <td>密码</td>
                <td>
                    <input type="password" placeholder="输入密码" maxlength="16" name="password" onfocus="clear_login_msg()">
                </td>
            </tr>
            <input type="hidden" value="普通用户" name="type">
            
            <tr>
                <input type="submit" name="submit" value="登录"/>
            </tr>
        </table>    
    </form>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值