Servlet
现在我们写代码,基本都是各种框架用的飞起,提起Servlet,感觉是很久远的事情了...
但无论怎样,Servlet都是基础,各种框架都是在Servlet的基础上封装的。这篇,我们来复习下Servlet。
首先,我们先了解几个硬性概念。
1、什么是Servlet?
--简单来说Servlet就是用java编写的服务器端代码。
2、Servlet的生命周期?
1)、Web服务器首先检查是否已经装载并创建了该Servlet的实例对象;
2)、装载并创建该Servlet的一个实例对象;
3)、调用Servlet的init()方法;
4)、创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个响应Http的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去;
5)、Web应用程序被停止或重新启动之前 ,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
3、Servlet接口实现类?
--GenericServlet、HttpServlet(常用)
4、关于web.xml配置?
--由于客户端是通过url地址访问web容器中的资源,所以Servlet程序若想被外界访问,必须把Servlet程序映射到一个url地址上,这个工作由web.xml中<servlet>元素和<servlet-mapping>元素完成。
如:
<servlet> <servlet-name>UserServlet</servlet-name> <servlet-class>com.rain.controller.UserServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UserServlet</servlet-name> <url-pattern>/UserServlet</url-pattern> </servlet-mapping>
<servlet>元素用于注册Servlet,它包含两个元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
<servlet-mapping>元素用于映射一个已注册的Servlet的对外访问路径,它包含两个元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。
需要注意的是:
1)、一个<servlet>可以对应多个<servlet-mapping>,即Servlet可以有多个对外访问路径;
2)、url-pattern中的路径也可以使用*通配符,但只有两种格式:一种是*.扩展名,另一种是以 /开头,/*结尾。
优先级判断如下:
1)、哪个精确找哪个;
2)、*.后缀的格式匹配度最低。
5、Servlet中的线程安全问题?
当多个客户端并发访问同一个Servlet的时候,web服务器会为每个客户端的请求创建一个线程,并在这个线程上调用Servlet的service()方法,但是Servlet在内存中只有一个对象,因此service方法内部如果访问了同一个资源的话,就有可能引发线程安全问题。
解决方案:
1)、使用SingleThreadModel接口:不能真的防止线程安全问题(已过时);
2)、使用同步代码块(效率低下)。
需要考虑线程安全的情况:
1)、访问类变量(成员变量);
2)、访问共享资源。
最终解决方案:在Servlet中尽量减少使用类变量(成员变量),如果一定要使用类变量则用锁来防止线程安全问题。但是要注意,锁住的内容应该是造成线程安全问题的核心代码,尽量的少锁主内容,减少等待时间提高Servlet的响应速度。
OK,理论上的内容讲完了,闲话少说,贴代码,自己写的一个登录注册的例子,代码可以直接拿去用,但没有cs之类的。
环境:JDK7+Tomcat8+MySQL8
项目架构:
Entity:
package com.rain.entity;
/**
* @author 047493
* @version 2019年5月21日
* entity:实体模型层
* User:实体类
*/
public class User {
private int id;
private String userName;
private String password;
private String email;
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getUserName(){
return userName;
}
public void setUserName(String userName){
this.userName = userName;
}
public String getPassword(){
return password;
}
public void setPassword(String password){
this.password = password;
}
public String getEmail(){
return email;
}
public void setEmain(String email){
this.email = email;
}
@Override
public String toString(){
return "User [id=" +id+ ",userName=" +userName+ ",password=" +password+ ",email=" +email+"]";
}
}
Controller:
package com.rain.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.rain.entity.User;
import com.rain.service.UserService;
import com.rain.service.impl.UserServiceImpl;
/*@WebServlet("/UserServlet")*/
public class UserServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
UserService userService = new UserServiceImpl();
public UserServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String method = request.getParameter("method");
//如果传入的参数是login
if("login".equals(method)){
login(request,response);
}else if("regist".equals(method)){
regist(request,response);
}else if("toLogin".equals(method)){
toLogin(request,response);
}else if("logout".equals(method)){
logout(request,response);
}else if("toRegist".equals(method)){
toRegist(request,response);
}else {
request.setAttribute("msg", "该功能正在开发。。。");
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
}
//注册
private void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User user = new User();
//获取前台jsp页面参数
String userName = request.getParameter("userName");
String password = request.getParameter("password");
String email = request.getParameter("email");
//将接收到的参数封装到user对象中去
user.setUserName(userName);
user.setPassword(password);
user.setEmain(email);
//判断用户名密码是否为空
//if(StringUtils.isNotBlank(user.getUserName()) && StringUtils.isNotBlank(user.getPassword())){
if((userName != null && userName.length() != 0)&&(password != null && password.length() != 0)){
int rows = userService.userRegister(user);
if(rows > 0){
response.setHeader("refresh", "1;url=UserServlet?method=toLogin");
} else {
response.setHeader("msg", "注册失败!");
request.getRequestDispatcher("/message").forward(request, response);
}
} else {
request.setAttribute("msg", "用户名密码不允许为空!");
request.getRequestDispatcher("/message").forward(request, response);
}
}
//登录
public void login(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{
//获取前台jsp表单传递的参数
String userName = request.getParameter("userName");
String password = request.getParameter("password");
//根据参数进行判断
//1、用户名密码均不为空
//if(StringUtils.isNotBlank(userName) && StringUtils.isNotBlank(password)){
if((userName != null && userName.length() != 0)&&(password != null && password.length() != 0)){
//2、传递到service层登录方法
User user = userService.userLogin(userName, password);
//3、判断用户信息是否查询得到
if(user != null){
//查询到,存入session
request.getSession().setAttribute("USER_SESSION", user);
//登录成功,跳转至主页
request.getRequestDispatcher("/WEB-INF/jsp/main.jsp").forward(request, response);
}else{
//未查询到或者用户名密码不匹配,会将失败的信息存储到msg中
request.setAttribute("msg", "用户名或密码错误!");
//登录失败,转向错误信息提示页,根据存入的msg取出相对应的内容
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
}else{
//如果用户名或密码为空
request.setAttribute("msg", "用户名密码不允许为空!");
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
}
}
//转向注册
private void toRegist(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/jsp/regist.jsp").forward(request, response);
}
//注销
private void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getSession().invalidate();
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
}
//转向到登录页面
private void toLogin(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
}
}
Service:接口+实现类
package com.rain.service;
import com.rain.entity.User;
/**
* @author 047493
* @version 2019年5月22日
* 业务逻辑层接口
*/
public interface UserService {
//用户登录
User userLogin(String userName,String password);
//用户注册
int userRegister(User user);
}
package com.rain.service.impl;
import com.rain.dao.impl.UserDaoImpl;
import com.rain.entity.User;
import com.rain.service.UserService;
/**
* @author 047493
* @version 2019年5月22日
* 业务逻辑层实现类
*/
public class UserServiceImpl implements UserService{
private UserDaoImpl userDao = new UserDaoImpl();
@Override
public User userLogin(String userName, String password) {
User user = userDao.login(userName, password);
return user;
}
@Override
public int userRegister(User user) {
return userDao.regist(user);
}
}
DAO:接口+实现类
package com.rain.dao;
import com.rain.entity.User;
/**
* @author 047493
* @version 2019年5月21日
* Dao:数据持久层接口
*/
public interface UserDao {
//登录
User login(String userName,String password);
//注册
int regist(User user);
}
package com.rain.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.rain.dao.UserDao;
import com.rain.entity.User;
import com.rain.util.DBUtil;
/**
* @author 047493
* @version 2019年5月21日
* Impl:数据持久层实现
*/
public class UserDaoImpl implements UserDao{
public static Connection conn;
public static PreparedStatement ps;
public static ResultSet rs;
@Override
public User login(String userName, String password) {
String sql = "select * from t_user where userName=? and password=?";
conn = DBUtil.getConnect();
User user = null;
try {
ps = conn.prepareStatement(sql);
ps.setString(1, userName);
ps.setString(2, password);
rs = ps.executeQuery();
while(rs.next()){
user = new User();
user.setId(rs.getInt("id"));
user.setUserName(rs.getString("userName"));
user.setPassword(rs.getString("password"));
user.setEmain(rs.getString("email"));
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return user;
}
@Override
public int regist(User user) {
String sql="insert into t_user(userName,password,email) values(?,?,?)";
conn = DBUtil.getConnect();
int i = 0;
try {
ps = conn.prepareStatement(sql);
ps.setString(1, user.getUserName());
ps.setString(2, user.getPassword());
ps.setString(3, user.getEmail());
ps.executeUpdate();
i = 1;
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return i;
}
}
Util:数据库连接类
package com.rain.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
/**
* @author 047493
* @version 2019年5月21日
* 数据库连接工具类
*/
public class DBUtil {
public static Connection conn;
public static PreparedStatement ps;
public static ResultSet rs;
static{
try {
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("加载数据库驱动成功!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnect(){
Properties p = new Properties();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream in = classLoader.getResourceAsStream("db.properties");
String username = null;
String password = null;
String url = null;
try {
p.load(in);
username = p.getProperty("username");
password = p.getProperty("password");
url = p.getProperty("url");
} catch (IOException e) {
e.printStackTrace();
}
if(conn == null){
try {
conn = DriverManager.getConnection(url,username,password);
System.out.println("数据库连接成功!");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return conn;
}
public static void CloseConnection(){
try {
if(rs != null){
rs.close();
}
if(ps != null){
ps.close();
}
if(conn != null){
conn.close();
}
}catch (SQLException e) {
e.printStackTrace();
}
}
}
db.properties:
username=root
password=123456
url=jdbc:mysql://127.0.0.1:3306/login?serverTimezone=GMT
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>ServletProject</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.rain.controller.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/UserServlet</url-pattern>
</servlet-mapping>
</web-app>
index.jsp:
<%@ 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>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>首页</title>
</head>
<body>
<jsp:forward page="WEB-INF/jsp/regist.jsp"></jsp:forward>
</body>
</html>
message.jsp:
<%@ 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>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>错误信息提示页</title>
</head>
<body>
${msg}
</body>
</html>
login.jsp:
<%@ 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>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录页面</title>
</head>
<body>
<div class="page">
<a id="toRegist" href="${pageContext.request.contextPath}/UserServlet?method=toRegist">没有账号,去注册?</a>
<div class="login_form">
<form id="Login" name="Login" action="${pageContext.request.contextPath}/UserServlet?method=login" method="post">
<table>
<tr align="center">
<td>请输入用户名:<input type="text" name="userName" size="20"/></td>
</tr>
<tr align="center">
<td>请输入密码:<input type="password" name="password" size="20"/></td>
</tr>
<tr>
<td><input type="submit" value="登录"/></td>
</tr>
<tr>
<td><input type="reset" value="重置"/></td>
</tr>
</table>
</form>
</div>
</div>
</body>
</html>
main.jsp:
<%@ 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>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录成功页面</title>
</head>
<body>
<center>
<h3>
${sessionScope.USER_SESSION.userName},登录成功
</h3>
<hr/>
<h4>
<a href="${pageContext.request.contextPath}/UserServlet?method=logout">退出系统</a>
</h4>
</center>
</body>
</html>
regist.jsp:
<%@ 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>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>注册页面</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/UserServlet?method=regist" method="post">
<header>请填写表单</header>
<fieldset>
<a id="toLogin" href="${pageContext.request.contextPath}/UserServlet?method=toLogin">已有账号,直接登录</a>
<br/>
<br/>
<section>
<label>
<input type="text" name="userName">
<b>请输入用户名</b>
</label>
</section>
<section>
<label>
<input type="password" name="password">
<b>请输入密码</b>
</label>
</section>
<section>
<label>
<input type="text" name="email">
<b>请输入邮箱</b>
</label>
</section>
</fieldset>
<footer>
<button type="submit">提交注册</button>
</footer>
</form>
</body>
</html>
OK,访问路径:http://localhost:8080/项目名称/index.jsp 即可。