设置Servlet模板
再创建类就有了
模板代码
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ${Class_Name} extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException ,IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
Servlet线程安全问题
面试题:Servlet是否是单例的?
不是单例,但是一般情况下是单例,
如果Servlet实现了SingleThreadModel接口,该Servlet对象在第一次线程阻塞时会创建新的对象 – 已过时
出现原因
多个客户端访问同一个Servlet中的资源时,有可能会出现线程安全问题
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
private int num;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
num++;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
response.getWriter().println(num);
}
}
这里直接输入指定Servlet访问
单独运行
浏览器1运行【num++】,同时再开个浏览器运行访问【num++】,就会新开的num变成1+1+1=3
解决方案:
加锁、使用线程安全的类
1.将Servlet实现SingleThreadModel(已过时),因为当线程阻塞,就会创建新的Servlet对象
2.利用线程锁机制, synchronized或lock
经验:尽可能的不要使用成员变量,而是使用局部变量
实现SingleThreadModel接口
public class Servlet01 extends HttpServlet implements SingleThreadModel{
public Servlet01() {
System.out.println("Servlet01被创建了");
}
......
}
添加无参构造,实现接口
再运行
未实现接口输出个数【单例】
实现接口,在阻塞【非单例】情况下会创建新的servlet对象,虽然解决了问题,但不可取
加锁
@WebServlet("/ser01")
//public class Servlet01 extends HttpServlet implements SingleThreadModel {
public class Servlet01 extends HttpServlet {
public Servlet01() {
System.out.println("Servlet01被创建了");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
private int num;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
synchronized (this){
num++;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
response.getWriter().println(num);
}
}
}
跳转
方式:转发和重定向
欢迎页面:
情况:
- 页面 跳 页面
- 页面 跳 Servlet
页跳s01
页跳s02
页跳s03
- Servlet 跳 Servlet
s跳s01
s跳s02
- Servlet 跳 页面
s跳页01
s跳页02
页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>页面 跳 页面</h1>
<a href="page01.html">跳转到页面1</a><br />
<button onclick="fun01()">跳转到页面1</button><br />
<form action="page01.html" method="post">
<input type="submit" value="跳转到页面1">
</form><br />
<h1>页面 跳 Servlet</h1>
<a href="ser01?username=xxx&password=123&nickname=爽了">跳转到Servlet01</a><br /><!--get请求-->
<button onclick="fun02()">跳转到Servlet01</button><br /><!--get请求-->
<form action="ser01" method="post"><!--可选请求方式-->
账号:<input type="text" name="username"><br />
密码:<input type="password" name="password"><br />
昵称:<input type="text" name="nickname"><br />
<input type="submit" value="跳转到Servlet01">
</form><br />
<h1>Servlet 跳 Servlet</h1>
<p>转发方式:Servlet02 -> Servlet03</p>
<p>浏览器地址栏输入:http://localhost:8080/MyDay18_Web03_war_exploded/ser02</p>
<p>重定向方式:Servlet04 -> Servlet05</p>
<p>浏览器地址栏输入:http://localhost:8080/MyDay18_Web03_war_exploded/ser04</p>
<h1>Servlet 跳 页面</h1>
<p>转发方式:Servlet06 -> page02.html</p>
<p>浏览器地址栏输入:http://localhost:8080/MyDay18_Web03_war_exploded/ser06</p>
<p>重定向方式:Servlet07 -> page03.html</p>
<p>浏览器地址栏输入:http://localhost:8080/MyDay18_Web03_war_exploded/ser07</p>
<script type="text/javascript" >
function fun01(){
window.location = "page01.html";
}
function fun02() {
window.location = "ser01?username=xxx&password=123&nickname=爽了";
}
</script>
</body>
</html>
java代码
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
String nickname = request.getParameter("nickname");
System.out.println("Servlet01接收到来自客户端的请求了:" + username + " -- " + password + " -- " + nickname);
response.getWriter().println(username + " -- " + password + " -- " + nickname);
}
}
@WebServlet("/ser02")
......
//doPost方法不同
//转发方式
request.getRequestDispatcher("ser03").forward(request,response);
@WebServlet("/ser03")
......
//doPost方法不同
System.out.println("Servlet03接受到请求了");
@WebServlet("/ser04")
......
//doPost方法不同
//重定向方式
response.sendRedirect("ser05");
@WebServlet("/ser05")
......
//doPost方法不同
System.out.println("Servlet05接受到请求了");
@WebServlet("/ser06")
......
//doPost方法不同
//转发方式
request.getRequestDispatcher("page02.html").forward(request,response);
@WebServlet("/ser07")
......
//doPost方法不同
//重定向方式
response.sendRedirect("page03.html");
转发和重定向的区别
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* 知识点:转发和重定向的区别
*/
//区别一:发送请求次数的区别
//注意:转发发送1次请求
//request.getRequestDispatcher("page01.html").forward(request,response);//http://localhost:8080/Day18_04_war_exploded/ser01
//注意:重定向发送2次请求
//response.sendRedirect("page01.html");//http://localhost:8080/Day18_04_war_exploded/page01.html
//区别二:访问外部资源
//注意:转发不能访问外部资源(因为服务器不能访问其他的服务器)
//request.getRequestDispatcher("https://www.baidu.com").forward(request,response);
//注意:重定向可以访问外部资源(因为本服务器通过响应告诉客户端重新向其他服务器发送请求)
//response.sendRedirect("https://www.baidu.com");
//区别三:访问受保护的页面
//注意:转发可以访问受保护的页面(因为转发是服务器内部的跳转)
//request.getRequestDispatcher("WEB-INF/page02.html").forward(request,response);
//注意:重定向不可以访问受保护的页面(因为客户端不能直接访问受保护文件夹里的资源)
response.sendRedirect("WEB-INF/page02.html");
}
}
受保护的页面,放在web\WEB-INF
<h1>受保护的页面</h1>
页面
<h1>页面1</h1>
转发
重定向
中文页面
设置请求和响应的编码格式不能解决,对应跳转中文页面还需加编码类进行设置
跳转中文页面地址栏就不会显示乱码和找不到
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置请求和响应的编码格式
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//跳转中文页面
// response.sendRedirect("页面1.html");
response.sendRedirect(URLEncoder.encode("页面1.html","UTF-8"));
}
}