实现一个简单的Servlet程序的步骤:
public class HelloServlet implements Servlet {
/**
* service 方法是专门用来处理请求和响应的
* @param servletRequest 客户端的请求
* @param servletResponse 服务器的响应
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws
ServletException, IOException {
System.out.println("Hello Servlet");
}
}
HelloServlet
com.lyh.servlet.HelloServlet
HelloServlet
/hello
public class HelloServlet implements Servlet {
public HelloServlet(){
System.out.println("1. 构造器方法被调用");
}
//这里使用了 ServletConfig这个类
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("2. 初始化方法被调用");
}
/**
* service是专门用来处理请求和响应的
* 当需要查询服务器并且不包含敏感数据时,可以使用GET方法。而当需要向服务器发送大量数据或包含敏感数据时,则应使用POST方法。
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("3 service()方法被调用 Hello Servlet");
}
@Override
public void destroy() {
System.out.println("4. destroy()方法被调用");
}
}
因为 service方法是专门用来处理客户端请求和返回响应的,所以使用该方法需要我们用户根据自己的需求来实现相关的方法完成对不同类型请求(GET/POST)的处理。
当需要查询服务器并且不包含敏感数据时,可以使用GET方法。而当需要向服务器发送大量数据或包含敏感数据时,则应使用POST方法。
由于我们继承的是Servlet接口,它没有直接对GET和POST这两种请求类型的区分,所以需要我们自己来实现区分并做不同的处理。
public class HelloServlet implements Servlet {
/**
* service 方法是专门用来处理请求和响应的
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws
ServletException, IOException {
System.out.println("3 service === Hello Servlet 被访问了");
// 类型转换(因为它有 getMethod()方法)
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
// 获取请求的方式
String method = httpServletRequest.getMethod();
if ("GET".equals(method)) {
doGet();
} else if ("POST".equals(method)) {
doPost();
}
}
/**
* 做 get 请求的操作
*/
public void doGet(){
System.out.println("get 请求");
}
/**
* 做 post 请求的操作
*/
public void doPost(){
System.out.println("post 请求");
}
}
通过上面的案例我们可以看到,直接继承Servlet接口很不方便,因为它毕竟只是一个接口,只对方法进行了规范并没有实现,我们看看Servlet接口的源码:
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
实际开发中我们很少直接继承Servlet接口去实现servlet程序 而是继承它的子类HttpServlet,因为HttpServlet这个抽象子类对Servlet的方法都进行了实现而且对GET/POST请求也添加了专门的方法去实现。
HttpServlet为GET/POST这两种客户端请求封装了两个方法,使得我们实现自己的业务逻辑更加简单明了。
public class HelloServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloServlet2 的 doGet 方法");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloServlet2 的 doPost 方法");
}
}
每一个Servlet类都需要配置web.xml:
HelloServlet2
com.lyh.servlet.HelloServlet2
HelloServlet2
/hello2
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration getInitParameterNames();
}
通过源码,我们可以了解到它的三大作用:
需要在我们的Servlet程序的配置信息中添加
HelloServlet
com.lyh.servlet.HelloServlet
url
jdbc:mysql://localhost:3306/test
username
root
public class HelloServlet implements Servlet {
//继承了HttpServlet的类在重写init时 一定要调用父类的初始化方法
super.init(config);
//这里使用了 ServletConfig这个类
@Override
public void init(ServletConfig servletConfig) throws ServletException {
// 1、可以获取 Servlet 程序的别名 servlet-name 的值
System.out.println("HelloServlet 程序的别名是:" + servletConfig.getServletName());
// 2、获取初始化参数 init-param
System.out.println("初始化参数 username 的值是;" + servletConfig.getInitParameter("username"));
System.out.println("初始化参数 url 的值是;" + servletConfig.getInitParameter("url"));
// 3、获取 ServletContext 对象
ServletContext context = servletConfig.getServletContext();
}
}
注意:
继承了HttpServlet的类在重写init时 一定要调用父类的初始化方法
super.init(config);
username
context
password
root
读取配置工程文件web.xml参数用 getInitParameter() 方法。
/**
* 不同于ServletConfig的标签
* 的作用域是它自己对应的Servlet程序
* 的作用域是每个Servlet程序
*/
public class ContextServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取配置文件中的参数
ServletContext context = getServletContext();
String username = context.getInitParameter("username");
System.out.println("context-param 参数 username 的值是:" + username);
//2.获取当前工程路径 /JavaWebStudy_war_exploded
System.out.println("当前工程路径 ="+context.getContextPath());
//获取工程部署在服务器上的绝对路径 D:\IdeaProjects\JavaWebStudy\target\JavaWebStudy-1.0-SNAPSHOT\
//斜杠 / 被服务器解析为 http://127.0.0.1:8080/JavaWebStudy/ 映射到idea的web目录
System.out.println("工程部署的绝对路径是 ="+context.getRealPath("/"));
System.out.println("工程下 css 目录的绝对路径是:" + context.getRealPath("/css"));
}
}
读取数据用 getAttribute() 方法 。
因为ServletContext的作用域是整个web工程,所以不同Servlet程序之间也可以共享参数以及自己配置参数供其他Servlet读取。
例:写两个Servlet类,Servlet1负责设置参数数据,Servlet2负责读取参数数据。
public class ContextServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
context.setAttribute("username","root");
context.setAttribute("password","123456");
}
}
public class ContextServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(getServletContext().getAttribute("username"));
System.out.println(getServletContext().getAttribute("password"));
}
}
注意:
这两个不一样
- 读取配置工程文件web.xml参数用 getInitParameter() 方法
- 读取数据用 getAttribute() 方法
我们可以看到service()方法里有两个参数,分别对应客户端的请求以及我们服务端的响应。
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws
ServletException, IOException {
//用户业务逻辑代码。。。
}
通过html中的表单提交数据,通过Servlet程序读取表单中的数据。
Title
Servlet只需要实现doGet方法即可。
注意:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求体的字符集为 UTF-8 解决post的请求乱码问题
//必须放在获取请求参数getParameter()方法之前调用才有效果
req.setCharacterEncoding("UTF-8");
System.out.println("URI => "+req.getRequestURI());
System.out.println("URL => "+req.getRequestURL());
System.out.println("客户端Host的ip => "+req.getRemoteHost());
// 我的真实ip 10.49.xx.xxx 可通过网络管理查看ipv4地址 就是本地真实地址
System.out.println("请求头 => "+req.getHeader("User-Agent"));
System.out.println("请求的方法 => "+req.getMethod());
// 参数名称就是 标签中的 name属性
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobby = req.getParameterValues("hobby");
System.out.println("请求的参数 username => "+username);
System.out.println("请求的参数 password => "+password);
System.out.print("请求的参数 hobby => ");
//打印数组的两种方式 1. Arrays.toString Arrays.asList(数组名)
System.out.println(Arrays.toString(hobby));
// System.out.println(Arrays.asList(hobby));
}
核心代码:
req.getRequestDispatcher("转发路径").forward(req,resp);
实例:客户端请求 /forwardc的资源, 由ForwardC这个Servlet程序转发到http://localhost:8080/JavaWebStudy_war_exploded/a/b/c.html。
需要再我们上面的html中添加超链接(我们的ForwardC对应的工程url为"/forwardc")。
Title
跳转到c.html
通过请求转发跳转到c.html
请求重定向到c.html
public class ForwardC extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("经过了ForwardC请求转发到了 c.html");
//转发到http://localhost:8080/JavaWebStudy_war_exploded + /a/b/c.html
//这里的斜杠 / 是协议//ip:端口号/工程路径的意思
req.getRequestDispatcher("/a/b/c.html").forward(req,resp);
}
}
c页面
C页面
回到首页
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//回传中文字符串同样会乱码,需要设置编码格式
//1.1这里设置的是我们服务器的编码格式 如果客户的浏览器不是UTF-8仍然是乱码
// resp.setCharacterEncoding("UTF-8");
//1.2通过响应头来设置浏览器编码
// resp.setHeader("Content-Type","text/html; charset=UTF-8");
//2.设置相应内容的格式 这种方法可以同时设置服务器和浏览器的编码格式
resp.setContentType("text/html; charset=UTF-8");
/**
* 字符流和字节流只能用一个
*/
//字符流 回传字符串 展示到html上
PrintWriter writer = resp.getWriter();
writer.write("Hello Response");
}
}
/**
* 请求重定向
*/
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet程序接收到用户请求");
//设置重定向的两种方法
//设置响应状态码 302 ,表示重定向,(已搬迁)
resp.setStatus(302);
//1. 设置响应头,说明 新的地址在哪里 不推荐
// resp.setHeader("Location", "http://localhost:8080");
//2.第二种方法 推荐使用
resp.sendRedirect("http://localhost:8080/JavaWebStudy_war_exploded/a/b/c.html");
}
}