一. GET和POST使用场景(建议)
- 查询数据是用GET,因为通常查询条件较小
- 提交数据(表单)时用POST,因为通常提交的数据较多
二. 增加员工案例
当前页面是查询页面:/EmpMangager/findEmp
FindEmpServlet.java
package Web;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.jasper.tagplugins.jstl.core.Out;
import dao.EmpDao;
import dao.EmpDaoImpl;
import entity.emp;
public class FindEmpServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
//1.接收参数(没有)
//2.处理业务(查询)
EmpDao dao =new EmpDaoImpl();//实例化dao
List<emp> list=dao.findAll();
//3.输出响应(表格)
res.setContentType("text/html;charset=utf-8");
PrintWriter out = res.getWriter();
out.println("<a href='add_emp.html'>增加</a>");//超链接路径是目标路径的相对路径
out.println("<table border='1' cellspacing='0' width='40%'> ");
out.println(" <tr>");
out.println(" <td>编号</td>");
out.println(" <td>姓名</td>");
out.println(" <td>职位</td>");
out.println(" <td>月薪</td>");
out.println(" </tr>");
if(list!=null){
for (emp e : list) {
out.println("<tr>");
out.println(" <td>"+e.getEmpno()+"</td>");
out.println(" <td>"+e.getEname()+"</td>");
out.println(" <td>"+e.getJob()+"</td>");
out.println(" <td>"+e.getSal()+"</td>");
out.println("</tr>");
}
}
out.println("</table>");
out.close();
}
}
web.xml
<servlet-name>findEmp</servlet-name>
<servlet-class>Web.FindEmpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>findEmp</servlet-name>
<url-pattern>/findEmp</url-pattern>
</servlet-mapping>
目标是增加页面:/EmpManager/add_emp.html
相对路径是:add_emp.html
add_emp.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 当前路径:/add_emp.html
目标路径:/addEmp -->
<form action="addEmp" method="post">
<p>
姓名:<input type="text" name="ename"/>
</p>
<p>
职位:<input type="text" name="job"/>
</p>
<p>
月薪:<input type="text" name="sal"/>
</p>
<p>
<input type="submit" value="保存"/>
</p>
</form>
</body>
</html>
点击保存后调用访问/addEmp
AddEmpServlet.java
package Web;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.jasper.tagplugins.jstl.core.Out;
import dao.EmpDao;
import dao.EmpDaoImpl;
import entity.emp;
public class AddEmpServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
//1.接收参数
req.setCharacterEncoding("utf-8");//处理POST方式中文乱码
String ename = req.getParameter("ename");
String job = req.getParameter("job");
String sal= req.getParameter("sal");
//2.处理业务
emp e = new emp();
e.setEname(ename);
e.setJob(job);
if(sal!=null&&!sal.equals("")){
e.setSal(new Double(sal));//自动装箱
}
EmpDao dao=new EmpDaoImpl();
dao.save(e);
3.输出响应
res.setContentType("text/html;charset=utf-8");
PrintWriter out =res.getWriter();
out.println("<p>保存成功</p>");
out.close();
}
}
保存成功后重定向到查询页面
//重定向到查询页面,就是建议浏览器访问查询页面
//当前路径:/EmpManager/addEmp
//目标路径:/EmpMaager/findEmp
res.sendRedirect("findEmp");入代码片
三. 重定向
1. 经典的使用场景
- 解决两个网站之间的跳转问题
2. 增加的场景
- 解决一个网站内两个独立组件之间的跳转(302代码)
- 一般增加、修改、删除后重定向到查询
四. 路径
1.什么是路径
建议: 将访问路径理解为一个资源的名字
2.URI和URL的区别
1)狭义的理解
- 只在Java中理解URI和URL
- URI:绝对路径
- URL:完整路径
从表面上看URI包含URL
2) 广义的理解(*)
- 在任意的WEB项目中理解URI和URL
- URI:资源的名称(可以有多个)。
- URL:资源的真名(只能有一个)。
URI包含URL
3. 如何配置Servlet访问路径即web.xml文件
1)精确匹配
- 举例:/abc
- 只有/abc才能访问此Servlet
- 此Servlet只能处理这一个要求
适合小规模项目
2)通配符
- 举例:/*
- 所有的路径都能访问此Servlet
- 此Servlet能处理所有请求
适合一个项目只写一个Servlet
3) 后缀
- 举例:*.hi
- 所有以hi为后缀的请求都能访问此Servlet
- 此Servlet能处理多个请求
适合一个项目写少量的几个Servlet
4. 使用一个Servlet处理多个请求
五. Servlet生命周期
六. ServletConfig和ServletContext
1.他们的作用
2. 它们的区别
1)config
- 和Servlet是一一对应关系
- Tomcat在初始化每一个Servlet前都会创建一个Config
- 调用XXServlet.init()前给他创建一个config
- 如果想给某个Servlet预制数据,使用config
2) context
- 和Servlets是一对多关系
- Tomcat在启动时就创建唯一的一个context
- 所有的Servlet都可以共享这个对象中的数据
- 如果想给多个Servlet预制数据,使用context
3. 它们的应用
1)config
- 需求:假设要开发一个网页游戏,当用户超出最大在线人数时要排队。登陆时判断是否已到达最大人数。
- 登陆:LoginServlet
- 最大人数:maxOnline,可以配置
- 该参数只需要LoginServlet使用,用config读取即可
web.xml设置参数
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>web.LoginServlet</servlet-class>
<init-param>//设置参数maxOnline
<param-name>maxOnline</param-name>
<param-value>3000</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
LoginServlet.java
package web;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
/*Tomcat创建servlet逻辑:
* LoginServlet s= new LoginServlet();
* ServletConfig c= new ServletConfig
* c.加载数据();从web.xml中加载数据
* s.init(c)*/
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
String maxOnline = config.getInitParameter("maxOnline");//读取设定的参数
System.out.println(maxOnline);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
ServletConfig cfg=getServletConfig();//init()传入的那个config
String maxOnline=cfg.getInitParameter("maxOnline");
System.out.println(maxOnline);
System.out.println("正在登录...");
}
}
2)context
- 软件内有很多查询功能,都带有分页功能
- 每页显示的行数size是常量,并且可配置
- 该数据再多个查询功能之间共用,用context读取
web.xml 设置参数
<!-- 在标签外配置的参数是给所有Servlet共用的参数,他们都可以通过context读取该参数 -->
<context-param>
<param-name>size</param-name>
<param-value>20</param-value>
</context-param>
FindEmpServlet.java
package web;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FindEmpServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
/*
* tomcat启动时就会创建唯一的context,并且会调用它的方法加载web.xml中的公用参数
* context是全局的,任何servlet都可以使用
*/
ServletContext ctx = getServletContext();
String size = ctx.getInitParameter("size");
System.out.println(size);//size在多个servlet中都要使用
System.out.println("分页查询员工数据");
}
}
FindDeptServlet.java
package web;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FindDeptServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
/*tomcat启动时就会创建唯一的context,并且会调用它的方法加载web.xml中的公用参数
* context是全局的,任何servlet都可以使用
* */
ServletContext ctx = getServletContext();
String size = ctx.getInitParameter("size");
System.out.println(size);
System.out.println("分页查询部门数据");
}
}
4.context的特殊用法
- 前提:之前使用config和context读取的是常量
- 而context还有能力读写变量
- 用该对象读写的变量是可以被所有servlet共用
- 使用setAttribute/getAttribute读取变量
- 案例:开发流量统计功能,无论访问哪个功能,流量+1
- 由于流量是变量,并且在多功能之间共用,所以用context
设置变量初始值 InitServlet.java
package web;
import java.util.concurrent.CountDownLatch;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
public class InitServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
//tomcat启动时会优先创建context然后再创建servlet
ServletContext context=getServletContext();
context.setAttribute("count", 0);
}
/*该Servlet不负责处理具体的业务,只用来在tomcat启动时初始化数据。
* 一般web项目都有1-2个这样的servlet*/
}
读取变量
Integer count = (Integer) ctx.getAttribute("count");
ctx.setAttribute("count", ++count);
System.out.println(count);
5. 总结
- 当需要给Servlet预置参数时使用这样的对象
- 若参数只给一个Servlet使用,用config
- 若参数给多个Servlet共用,用context
七. Servlet层次结构
1.整体结构
2. HttpServlet
八. Servlet线程安全问题
1. 同时修改局部变量
- 局部变量存在栈内
- 每个线程有自己的栈帧
此时没有线程问题
2. 同时修改成员变量
- 成员变量存在堆内
- 所有线程共享这样的数据
此时存在线程安全问题
3. 解决方案
- 加锁
package web;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class UpServlet extends HttpServlet {
double salary = 2000.0;
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
synchronized (this) {
//模拟涨薪
salary+=100;
//网络延迟
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//显示数据
res.setContentType("text/html;charset=utf-8");
PrintWriter out=res.getWriter();
out.println(salary);
out.close();
}
}
}