1.部署环境
使用工具:IDEA、tomcat、maven
新建一个maven项目。在maven项目中导入servlet依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
新建一个HelloServlet类进行测试。
public class HelloServlet extends HttpServlet {
//get和post只是实现请求的不同方式,可以互相调用,业务逻辑一样
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter();//响应流
writer.print("hello servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
在web.xml文件中注册该servlet
<!--注册servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.leo.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
之后发布tomcat进行测试
结果:
环境已经部署完成,接下来开始学习。
2. 注册servlet
<servlet>
<servlet-name>hello</servlet-name>//给该servlet起个名字,自定义
<servlet-class>com.leo.servlet.HelloServlet</servlet-class>//绑定该servlet类
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>//对应上面servlet的名字
<url-pattern>/hello</url-pattern>//设置浏览器访问的url地址
</servlet-mapping>
有servlet标签,就要对应有一个servlet-mapping标签。
class内绑定servlet类,注意该类必须是一个servlet类。
url-pattern栏中设置浏览器访问的url地址。如上图设置,最终访问的是 localhost:8080/hello
3.servlet类
如何让自己写的类成为一个servlet?
public class HelloServlet extends HttpServlet
只需要让我们的类继承HttpServlet类即可。
该类中存在着许多方法,我使用时一般需要重写其中的doGet以及doPost方法,根据需求,这两者相互调用即可
4.servlet中context的使用
4.1 传递数据
编写一个HelloServlet类
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//this.getInitParameter() 初始化参数
//this.getServletConfig() 初始化Servlet配置
//this.getServletContext() Servlet上下文
ServletContext context = this.getServletContext();
String name="林志玲";//数据
context.setAttribute("username",name);//将数据保存在了context中,名字为username,值为name
}
}
在servlet类中,通过this.getServletContext()可以获取Servlet的上下文context。
context.setAttribute方法则起到了数据储存的功能。
我们如何在别的servlet中获取该数据呢?编写另一个类GetServlet
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取context上下文
ServletContext context = this.getServletContext();
String username = (String) context.getAttribute("username");
resp.setCharacterEncoding("utf-8");//设置编码集防止乱码
resp.setContentType("text/html");//告诉浏览器以文本形式展示
PrintWriter writer = resp.getWriter();
writer.print(username);//展示在浏览器界面
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
首先通过this.getServletContext()获取上下文context。这里不同servlet类所获得的的context都会是同一个context。
context.getAttribute方法则是取得之前所保存的数据。名称需要一致(username)。
在web.xml中注册这两个servlet
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.leo.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getc</servlet-name>
<servlet-class>com.leo.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getc</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
此时我们首先访问HelloServlet: localhost:8080/hello将数据(username:林志玲)存入
在访问GetServlet:localhost:8080/getc 将(username:林志玲)获取并展示在网页:
4.2 获取配置参数
我们可以在web.xml中为servlet配置一些参数:
<!--配置web初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
同时也可以通过context将它们取得。
编写类:
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取context上下文
ServletContext context = this.getServletContext();
//获取配置中的信息
String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
依然先获取context对象。
通过context.getInitParameter方法获取参数(url),打印在网页上。
注册servlet:
<servlet>
<servlet-name>gp</servlet-name>
<servlet-class>com.leo.servlet.ServletDemo03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gp</servlet-name>
<url-pattern>/gp</url-pattern>
</servlet-mapping>
4.3 转发页面
在我们访问一个页面的时候,通过转发功能,会跳转到另外一个指定的页面
编写类:
public class ServletDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取context上下文
ServletContext context = this.getServletContext();
System.out.println("进入Demo04");
//获取转发器
RequestDispatcher dispatcher = context.getRequestDispatcher("/gp");//转发的请求路径
dispatcher.forward(req,resp);//调用foreword方法进行转发
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
context.getRequestDispatcher方法获取转发器,其参数就填你所要转发的路径,这里转发到上一个页面 localhost:8080/gp。
dispatcher通过forward(req,resp)方法进行页面转发。
注册servlet:
<servlet>
<servlet-name>sd4</servlet-name>
<servlet-class>com.leo.servlet.ServletDemo04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sd4</servlet-name>
<url-pattern>/sd4</url-pattern>
</servlet-mapping>
首先尝试访问 localhost:8080/sd4 :
发现url地址栏仍然是我们访问的 localhost:8080/sd4 ,然而页面却跳转到了 localhost:8080/gp 的内容,这就是转发功能。
4.4 获取配置文件以及其中的内容
通过context也是能够读取配置文件中的内容的,下面进行测试。
在resources文件夹下创建一个配置文件db.properties:
username=root
password=123456
写一个servlet类:
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
InputStream is = context.getResourceAsStream("/WEB-INF/classes/db.properties");//当前web下的路径
Properties prop = new Properties();
prop.load(is);
resp.getWriter().print(prop.getProperty("username"));
resp.getWriter().print(prop.getProperty("password"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
通过流的形式把配置文件读取。
getResourceAsStream()中的路径,不能直接填写"db.properties",必须填写其在web项目发布之后所存在的位置。寻找方法:
在target文件夹下-->找到所发布的web项目-->WEB-INF-->classes-->db.properties。
注册servlet:
<servlet>
<servlet-name>sd5</servlet-name>
<servlet-class>com.leo.servlet.ServletDemo05</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sd5</servlet-name>
<url-pattern>/sd5</url-pattern>
</servlet-mapping>
访问:
4.5 总结
自定义的servlet类必须继承HttpServlet,这样才代表着此类是一个servlet。
重写HttpServlet的doGet和doPost方法,两者可以互相调用。
需要在web.xml中注册自定义servlet类。
若要使用ServletContext中的功能,通过this.getServletContext,取得context对象,即可使用。
5.response的使用
5.1 下载文件
将一个图片文件放到resources文件夹下
自定义servlet类:
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取下载文件的路径
String realPath = "F:\\java\\idea\\javaweb\\response\\target\\response\\WEB-INF\\classes\\1.png";
System.out.println("下载文件的路径"+realPath);
//2.获取下载文件的文件名
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
//3.设置让浏览器支持下载我们的东西
resp.setHeader("Content-disposition","attachment;filename"+fileName);
//4.获取下载文件输入流
FileInputStream is = new FileInputStream(realPath);
//5.创建缓冲区
byte[] bytes = new byte[1024];
int len = 0;
//6.获取OutputStream对象
ServletOutputStream os = resp.getOutputStream();
//7.将OutputStream流写入buffer缓冲区,使用OutputStream将缓冲区中的数据输出到客户端
while ((len = is.read(bytes))>0){
os.write(bytes,0,len);
}
is.close();
os.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册servlet:
<servlet>
<servlet-name>down</servlet-name>
<servlet-class>com.leo.servlet.FileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>down</servlet-name>
<url-pattern>/down</url-pattern>
</servlet-mapping>
访问 localhost:8080/down 后即可下载该图片文件。
5.2 自定义图片
编写servlet类
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置浏览器3秒钟刷新一次
resp.setHeader("refresh","3");
//在内存中创建一个图片
BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D g = (Graphics2D) image.getGraphics();//笔
//设置背景颜色
g.setColor(Color.white);
g.fillRect(0,0,80,20);
//给图片写数据
g.setColor(Color.blue);
g.setFont(new Font(null,Font.BOLD,20));
g.drawString(makeNum(),0,20);
//告诉浏览器这是个图片,用图片的方式打开
resp.setContentType("image/jpeg");
//不让浏览器缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
//把图片写给浏览器
ImageIO.write(image,"jpg",resp.getOutputStream());
}
//生成随机数
public String makeNum(){
Random random = new Random();
String num = random.nextInt(9999999) + "";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 7-num.length(); i++) {
sb.append("0");
}
num=sb.toString()+num;
return num;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册servlet
<servlet>
<servlet-name>ImageServlet</servlet-name>
<servlet-class>com.leo.servlet.ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ImageServlet</servlet-name>
<url-pattern>/im</url-pattern>
</servlet-mapping>
访问:
5.3 重定向(重要)
前2个功能在应用场景不大,重定向功能则是resp十分重要的应用。
编写servlet类:
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("/im");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
resp的sendRedirect方法实现了重定向功能。方法的参数就填写你所要重定向到的页面。
注册servlet:
<servlet>
<servlet-name>redirect</servlet-name>
<servlet-class>com.leo.servlet.RedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>redirect</servlet-name>
<url-pattern>/red</url-pattern>
</servlet-mapping>
我们输入http://localhost:8080/red,访问到的地址却是im (80×20)。这就是重定向,地址栏会发生改变。
5.5 总结
response中最重要的应用是重定向,记住sendRedirect方法即可。
6.request的使用
6.1 获取参数
通过req.getParameter()方法,可以获取请求中携带的参数。
编写index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<h1>
登录
</h1>
<div style="text-align: center">
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobby" value="女孩">女孩
<input type="checkbox" name="hobby" value="代码">代码
<input type="checkbox" name="hobby" value="电影">电影
<input type="checkbox" name="hobby" value="运动">运动
<br>
<input type="submit">
</form>
</div>
</body>
</html>
这里我们通过表单的形式,能够上传我们所命名的属性:username、password、hobby
编写servlet:
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println("---------");
System.out.println(username + " " + password);
System.out.println("---------");
System.out.println(Arrays.toString(hobbies));
//通过request转发
req.getRequestDispatcher("/successful.jsp").forward(req,resp);
}
}
这里可以看到的是,我们使用了req.getParameter()方法,来获取上传到表单的参数,获取名字必须一致。
注册servlet:
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.leo.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
结果:
访问了登录页面后,展示的是index.jsp的界面。我们填好内容,并且提交后:
可以看到控制台确实获取到了我们的参数。
6.2 转发
转发是request中最常使用的方法,其功能是将此页面转发到另一页面,也是实现页面的跳转。
代码和6.1中一样。我们通过req.getRequest.Dispatcher("").forward(req,resp)的方法,实现了页面的转发。其中,第一个括号内要填的参数是你所要转发到的页面。
为了测试转发,在编辑一个successful.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>
successful!
</h1>
</body>
</html>
结果:
当我们点击提交后,跳转到了successful.jsp页面,完成了页面的转发。
6.3 request转发和response重定向的区别
相同点:都能实现页面的跳转
不同点:
转发:
可见的URL地址栏并未发生改变,仍然是跳转前界面的地址
重定向:
如上面,访问的是http://localhost:8080/red,然而跳转到此页面时,顶部的URL地址栏也发生了变化。
更多异同参考其他文档。