模块一 Servlet(上)
Tomcat服务器
- 默认访问ROOT文件夹下index文件
Servlet与前端页面
- 一个Java类
- 一种运行在服务器上的特殊类,可以给浏览器的请求做出响应
如何使用Servlet
第一步:创建Servlet类
- 继承Servlet类
- 实现HttpServlet接口(推荐)
- GenericServlet类
- HttpServlet类
- GenericServlet类
- 重写service方法
public class HelloServlet3 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("继承HttpServlet的方式创建,以后的开发中推荐该方式");
}
}
第二步: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">
<servlet>
<!--对Servlet起别名 习惯上使用类名-->
<servlet-name>HelloServlet</servlet-name>
<!--指定别名对应的Servlet类-->
<servlet-class>com.lagou.demo02.HelloServlet</servlet-class>
</servlet>
<!--与上面别名的映射关系-->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
HttpServlet类
生命周期
- 编写构造方法
- 重写init方法
- 重写service方法
- 重写destory方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-stFdvkwk-1607333997251)(C:\Users\miaoxun3\AppData\Roaming\Typora\typora-user-images\image-20201201131246371.png)]
- 多次请求/hello3,构造方法、init方法只会执行一次,只有service方法会被多次执行
- 停止服务器时会调用destory方法
GET和POST
1.创建Servlet
@WebServlet(name = "HelloServlet4", urlPatterns = "/hello4")
public class HelloServlet4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("POST请求发送成功");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("GET请求发送成功");
}
}
2.创建HTML页面
- 选择GET方式请求
- 浏览器直接URL访问
- a标签默认GET方式请求
- form表单提交默认GET方式请求
- 选择POST方式请求
- form表单method属性选择post,提交
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试请求</title>
</head>
<body>
<a href="hello4">测试链接</a>
<form action="hello4" method="post">
<button>提交</button>
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请求参数的获取</title>
</head>
<body>
<form action="paramsServlet" method="post">
姓名: <input type="text" name="name"><br>
年龄: <input type="text" name="age"><br>
爱好: <input type="checkbox" name="hobby" value="Java">Java
<input type="checkbox" name="hobby" value="C">C
<input type="checkbox" name="hobby" value="C++">C++<br>
<button>提交</button>
</form>
</body>
</html>
3.获得请求参数
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
//获取参数
String name = request.getParameter("name");
System.out.println("获取到的名字是" + name);
String age = request.getParameter("age");
System.out.println("获取到的年龄是" + age);
String[] hobbies = request.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
Enumeration<String> names = request.getParameterNames();
while (names.hasMoreElements()) {
String nextElement = names.nextElement();
System.out.println(nextElement);
}
Map<String, String[]> map = request.getParameterMap();
Set<Map.Entry<String, String[]>> entrySet = map.entrySet();
for (Map.Entry<String, String[]> entry : entrySet) {
String key = entry.getKey();
String[] value = entry.getValue();
System.out.println(key + "对应的值有" + Arrays.toString(value));
}
}
4.给客户端响应
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码方式及文本类型
response.setContentType("text/html;charset=UTF-8");
//给客户端发出响应
String encoding = response.getCharacterEncoding();
System.out.println(encoding);
PrintWriter writer = response.getWriter();
writer.println("已经收到!");
writer.close();
}
Servlet与JDBC
1.编写前端注册页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
</head>
<body>
<form action="register" method="post">
用户名:<input type="text" name="userName"><br>
密 码:<input type="password" name="password"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
2.获取前端输入表单信息
package com.lagou.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "RegisterServlet")
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
System.out.println("获取到的用户名是:" + userName);
System.out.println("获取到的密码是:" + password);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
3.创建实体类
package com.lagou.model;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 8913234752244427793L;
private int id;
private String userName;
private String password;
public User() {
}
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
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;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
4.DAO层
package com.lagou.dao;
import com.lagou.model.User;
import com.lagou.util.DbUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class UserDao {
public int register(User user) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
// 1.获取连接
connection = DbUtil.getConnection();
// 2.准备sql语句
String sql = "insert into t_user values(null, ?, ?)";
// 3.获取PrepareStatement类型的引用
preparedStatement = connection.prepareStatement(sql);
// 4.向问号所占的位置设置数据
preparedStatement.setString(1, user.getUserName());
preparedStatement.setString(2, user.getPassword());
// 5.执行sql语句
int row = preparedStatement.executeUpdate();
return row; // 执行成功
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 6.关闭资源
try {
DbUtil.closeConnection(connection, preparedStatement);
} catch (SQLException e) {
e.printStackTrace();
}
}
return 0; // 执行失败
}
}
重定向与转发
重定向
- response.sendRedirect()
package com.lagou.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "RedirectServlet",urlPatterns = "/redirect")
public class RedirectServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("接收到了浏览器请求");
response.sendRedirect("target.html");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
转发
- 将请求转发给另外一个Servlet
package com.lagou.servlet;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "TargetServlet", urlPatterns = "/target")
public class TargetServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("target");
request.setAttribute("key1", "value1");
request.setCharacterEncoding("utf-8");
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/forward");
requestDispatcher.forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
区别
- 重定向可以重定向给外部资源,转发只能转发给内部资源(其他Servlet)
- 重定向是告诉客户端,让客户端自己去重新请求资源
- 转发是服务端自己重新请求资源返回给客户端
Servlet线程安全问题
- java代码
package com.lagou.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "ThreadServlet",urlPatterns = "/thread")
public class ThreadServlet extends HttpServlet {
private String name;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
name = request.getParameter("name");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
PrintWriter writer = response.getWriter();
writer.write("<h1>" + name + "</h1>");
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
- html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试线程安全</title>
</head>
<body>
<iframe src="thread?name=guanyu" frameborder="0"></iframe>
<iframe src="thread?name=zhangfei" frameborder="0"></iframe>
<iframe src="thread?name=liubei" frameborder="0"></iframe>
</body>
</html>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zoqXgXYs-1607333997252)(C:\Users\miaoxun3\AppData\Roaming\Typora\typora-user-images\image-20201205101010717.png)]
- 解决方式
- 方法加锁
- name变量修改为局部变量,每次请求重新创建
状态管理
- 多次交互的数据状态保存
- 保存在客户端(Cookie)
- 保存在服务端(Session)
Cookie
- 客户端首次请求,服务器通过响应将Cookie传递给客户端(响应头)
- 客户端再次发起请求,带着cookie再次发起请求(请求头)
- 本地存储Cookie只有一个
生命周期
- 默认生命周期–>保存在内存中,浏览器关闭Cookie消失
- 使用setMaxAge(int expiry)设置最大时间,单位/秒
- expiry = 0 立即删除 存储里看不到
- expiry < 0 浏览器关闭后失效
- expiry > 0 在expiry秒后失效
路径
- setPath() 设置Cookie的路径
- 访问的请求地址必须符合Cookie的路径或者其子路径时,浏览器才会发送Cookie信息
特点
- 不适合存储所有数据,只用于存储少量非敏感信息
- 将数据存储在浏览器不安全
- 最多存储大约4KB数据
- 只能保存字符串信息
- 可以通过浏览器设置为禁止使用
Session
生命周期
- 为了节省资源,服务器会自动清理空闲时间过长的session对象,默认30分钟
- setMaxInactiveInterval(int interval) 设置失效时间
- 修改配置文件
<session-config>
<!--设置session超时时间为30分钟-->
<session-timeout>30</session-timeout>
</session-config>
特点
- 数据比较安全
- 能够保存的数据类型丰富,而Cookie只能保存字符串
- 能够保存更多的数据,而Cookie大约保存4KB
- 数据保存在服务器端会占用服务器的内存空间,如果存储信息过多、用户量过大,会严重影响服务器的性能。
JSP
- Java Server Pages
- 示例
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello JSP</title>
</head>
<body>
现在的时间是:<%=new Date()%>
</body>
</html>
语法结构
声明区
-
<%! %>
- 可以定义全局变量、方法、类
-
<% %>
- 可以定义局部变量以及放入任何的Java程序代码
-
<%= %>
- 可以输出一个变量或一个具体内容,但=后面必须是字符串变量或者可以被转换成字符串的表达式
- 不需要以;结束,只有一行
案例
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>绘制表格</title>
</head>
<body>
<table>
<tr>
<td>id</td>
<td>name</td>
<td>age</td>
<td>salary</td>
</tr>
<%
for (int i = 1; i < 6; i++) {
%>
<tr>
<td><%=i%>
</td>
<td><%=i%>
</td>
<td><%=i%>
</td>
<td><%=i%>
</td>
</tr>
<%
}
%>
</table>
</body>
</html>
注释
- HTML文件的注释,浏览器可以查看到
- <%–… …–%> JSP文件的注释,浏览器看不到
- <%//… …%> Java语言中的单行注释,浏览器看不到
- <%/… …/%> Java语言中的多行注释,浏览器看不到
指令和动作
- 指令格式<%@ 指令 属性=“属性值”>
- 指令的属性可以设置多个
page指令
- page指令经常用于导包和设置页面
- import 导入相应的包,惟一允许在同一文档中多次出现的属性
- contentType 设置Content-Type响应报头,标明即将发送到浏览器的文档类型
- pageEncoding 设置页面的编码
- language 指定页面使用的语言
- session 控制页面是否参与HTTP会话
- errorPage 处理当前页面中抛出但未被捕获的任何异常
- isErrorPage 当前页是否可以作为其他页面的错误处理页面
taglib指令
- taglib指令用来扩展JSP程序的标签元素,引入其他功能的标签库文件
include指令
- include指令用于引入另一个JSP程序或HTML文件等
- <%@include fil=“被包含的文件地址”>
内置对象
out内置对象
- 向客户端(浏览器)输出信息
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>out内置对象使用</title>
</head>
<body>
<%
out.print("hello world");
out.println("hello world");
out.println("<h1>你好</h1>");
//out.close();
int bufferSize = out.getBufferSize();
System.out.println("获得的缓冲区的字节数是" + bufferSize);
int remaining = out.getRemaining();
System.out.println("获得的缓冲区已使用的字节数是:" + remaining);
out.clear();
%>
</body>
</html>
request内置对象
- 一次请求内可以拿到设置的属性
- 再次请求拿不到
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>request</title>
</head>
<body>
<%
String serverName = request.getServerName();
out.println("服务器名称是:" + serverName);
%>
</body>
</html>
response内置对象
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
response.addHeader("refresh", "1");
Date d1 = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sdf.format(d1);
%>
<%= "当前时间为" + format%>
</body>
</html>
session内置对象
- 更换浏览器拿不到属性
application内置对象
- 服务启动中,更换浏览器也可以拿到属性
pageContext内置对象
- 只有当前页面可以拿到属性
等级
pageContext < request < session < application