Servlet就是sun公司开发动态web的一门技术
Sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成3个步骤:
把实现了Servlet接口的java程序叫做servlet
servlet在sun公司有两个默认继承类,Httpservlet,GenericServlet
构建一个普通的maven项目,删掉里面的src目录,以后我们的学习就在这个项目里面建立module了。这个空的工程就是maven主工程。详细见1.3
idea中查看继承关系树
方法一:
ctrl+H
方法二:
ctrl+alt+U
为什么需要映射:我们写的是java程序,但是要通过浏览器访问,而浏览器需要连接的web服务器,所以我们需要:
在web服务器中注册我们写的servlet
还需要给他一个浏览器能够访问的路径。
注意:配置项目发布的路径即可
1.3 关于maven 父子工程的理解
注意:有时候用idea创建子项目的时候,parent标签会丢失
,注意检查项目
父项目中会有
子项目中会有
PureMavenWeb
父项目中的java子项目可以直接使用,而子项目中的父项目不能使用。同多态一样。
注意:前面不能加映射的路径,如/hello/*.do
指定了固有的映射路径=》优先级最高。
如果找不到就会走默认的处理请求/*
initParam qcc contextParam admin
通过getServletConfig().getInitParameter("initParam")的方式获取;
通过getServletContext().getInitParameter("contextParam")的方式获取;
web容器在
启动的时候
,他会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用。(在容器启动时候就有)
作用:
我在这servlet中保存的数据,可以在另外一个servlet获取。
注意:实际工作中,一般不用servletContext存取数据,一般用session和COOKIE和request存取数据
一个servlet用于通过ServletContext来set数据
happyContextParam adminpackage com.happy.servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class SetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
ServletContext servletCOntext= this.getServletContext();
//
//
//
//
//
String happy = servletContext.getInitParameter("happyContextParam");
System.out.println(happy);
int i=0;
Object object= servletContext.getAttribute("happy");
if (object==null){
i=0;
} else {
i=(int)object+1;
}
servletContext.setAttribute("happy",i);
ServletConfig servletCOnfig= this.getServletConfig();
String happyServletParam = servletConfig.getInitParameter("happyServletParam");
System.out.println(happyServletParam);
PrintWriter writer = resp.getWriter();
writer.println("访问次数+1");
writer.println("http://localhost:8080/s2/get");
System.out.println(i);
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPut(req, resp);
}
}
一个servlet用于通过ServletContext来get数据
package com.happy.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletCOntext= this.getServletContext();
Object happy = servletContext.getAttribute("happy");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("访问次数共计:"+happy);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
web.xml如下
happyContextParam admin happyServletParam happyvalue
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
可以用来配置一些web应用初始化参数
注意:实际工作中一般不在web.xml中放参数,而用properties文件等存全局参数
happyContextParam admin setByConf setByConfValue
package com.happy.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class GetInitParamsServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletCOntext= this.getServletContext();
String setByCOnf= (String)servletContext.getInitParameter("setByConf");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("setByConf:"+setByConf);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
4.2.3 请求转发
实际工作中一般不用ContextServlet对象的dispatcher,而用response对象的dispatcher方法
package com.happy.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ContextDispatcherServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletCOntext= this.getServletContext();
servletContext.getRequestDispatcher("/get").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
实际工作中一般不用这个api,而是用反射和类加载等加载资源文件
对回被打包到同一个路径下:classes,我们俗称这个路径为classpath:
maven构建时候,部分source目录下面资源文件不能打包问题
解决方案:在build中配置resources.来防止我们资源导出失败的问题
写一个servlet调用context对象的获取资源文件的api方法getResourceAsStream
InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties");
package com.happy.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class PropertiesServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletCOntext= this.getServletContext();
InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties");
Properties prop = new Properties();
prop.load(is);
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
response.getWriter().println(url+" "+username+" "+password);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
效果如下:
web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个httpServeletResponse。
ServletOutputStream getOutputStream() throws IOException; //其他,如果老用中文会造成字符窜丢失
PrintWriter getWriter() throws IOException; //中文
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void setBufferSize(int var1);
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
void setStatus(int var1);
响应的状态码:
int SC_COnTINUE= 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_COnTENT= 204;
int SC_RESET_COnTENT= 205;
int SC_PARTIAL_COnTENT= 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_COnFLICT= 409;
int SC_GOnE= 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LOnG= 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
下载文件
resp.setHeader("Content-disposition","attachment;filename"+filename);核心:
resp.setHeader("Content-disposition","attachment;filename="+filename);
URLEncoder.encode(filename,"utf-8")) //解决文件名乱码
package com.happy.servlet;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
public class DownServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/* 1. 要获取下载文件的路径
2. 下载文件名是啥
3. 设置想办法让浏览器能够支持下载我们需要的东西
4. 获取下载文件的输入流
5. 创建缓存区
6. 获取OutputStream对象
7. 将FIleOutputStream流写入到buffer缓冲区
8. 使用outputstream将缓冲区中的数据输出到客户端*/
String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/书.jpg");
System.out.println(realPath);
String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);
System.out.println(filename);
// resp.setHeader("Content-disposition","attachment;filename"+filename);
String userAgent = req.getHeader("USER-AGENT");
if (StringUtils.contains(userAgent, "MSIE") || StringUtils.contains(userAgent, "Edge")) {
// IE浏览器
filename = URLEncoder.encode(filename, "UTF-8");
} else if (StringUtils.contains(userAgent, "Firefox") || StringUtils.contains(userAgent, "Chrome") || StringUtils.contains(userAgent, "Safari")) {
// google,火狐浏览器
// filename = new String(filename.getBytes(), "ISO-8859-1");
filename = URLEncoder.encode(filename, "UTF-8");
} else {
filename = URLEncoder.encode(filename, "UTF-8");
// 其他浏览器
}
System.out.println(filename);
resp.setHeader("Content-disposition", "attachment;filename=" + filename);
// 创建输入流,把文件变成流
FileInputStream is = new FileInputStream(realPath);
// 创建输出流
ServletOutputStream os = resp.getOutputStream();
// 创建缓存区,new 一个byte【】作为byte
byte[] buff = new byte[1024];
int len = 0;
try {
System.out.println("开始读取数据");
while ((len = is.read(buff)) > 0) {
os.write(buff, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
is.close();
os.close();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
原生生成验证码方法:
package com.happy.servlet;
import org.junit.jupiter.api.Test;
import javax.imageio.ImageIO;
import javax.servlet.*;
import javax.servlet.http.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 前端刷新为windows.location.refresh
// 通过后端响应给前端设置头信息,响应可以设置前端所有东西
response.setHeader("refresh","8");
BufferedImage bufferedImage=drawNum();
// 告诉浏览器,这个请求的响应用图片方式打开
response.setContentType("image/png");
// 取消缓存
response.setDateHeader("expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
boolean jpg = ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Test
public BufferedImage drawNum(){
// 在内存中创建一个空白的图片
BufferedImage bufferedImage = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();
// 设置图片的背景颜色
graphics.setColor(Color.white);
// 画边框
graphics.fillRect(0,0,80,20);
// 给图片写数据
graphics.setColor(Color.blue);
graphics.setFont(new Font(null,Font.BOLD,20));
graphics.drawString(makeNum(),0,20);
return bufferedImage;
}
public String makeNum(){
Random random = new Random();
String num = String.valueOf(random.nextInt(999999+1));
StringBuffer sb = new StringBuffer(num);
for(int i=0;i<=5-num.length();i++){
sb.append(0);
}
return sb.toString();
}
}
4.实现重定向
本质上是302和location设置重定向地址
response.sendRedirect();
常见场景:
package com.happy.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 方式一
// 可以直接重定向到外部网站
// response.sendRedirect("http://www.baidu.com");
// 也可以内部地址,要带项目名
response.sendRedirect("/response/image");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
所以本质上是302和location设置重定向地址
// 方式二,拆分两步
response.setHeader("Location","/response/image");
// response.setStatus(302);
response.setStatus(HttpServletResponse.SC_FOUND);
重定向 | 转发 | |
---|---|---|
相同点 | 页面实现跳转 | 页面实现跳转 |
不同点 | url地址栏会发生变化 | url不会产生变化 |
index.jsp作为登陆页面如下:
<%@ page cOntentType="text/html;charset=UTF-8" language="java" %>
<%--这里提交的路径,需要寻找项目的路径--%>
<%----%>
用户:
密码:
web.xml配置映射
处理servlet
package com.happy.servlet;
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 FormServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("进入这个请求了");
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(username+":"+password);
response.sendRedirect("/response/success.jsp");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
重定向 | 转发 | |
---|---|---|
相同点 | 页面实现跳转 | 页面实现跳转 |
不同点 | url地址栏会发生变化 | url不会产生变化 |
状态码 | 302 | 307 |
注意:重定地址(外部地址)要带项目名
获取方式:
写死response.sendRedirect("projectContextName/success.jsp");
this.getServletContext().getContextPath()
response.sendRedirect(this.getServletContext().getContextPath()+"/success.jsp");
request.getContextPath()
response.sendRedirect(request.getContextPath()+"/success.jsp");
注意:转发地址(内部地址)不用带项目名
package com.happy.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Arrays;
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(username+":"+password);
String[] hobbies = request.getParameterValues("hobbies");
System.out.println(Arrays.toString(hobbies));
System.out.println(this.getServletContext().getContextPath());
System.out.println(request.getContextPath());
// 方式一:response redirect转发
// response.sendRedirect(this.getServletContext().getContextPath()+"/success.jsp");
// 方式二:servletContext 重定向
// this.getServletContext().getRequestDispatcher("/success.jsp").forward(request,response);
//方式三:request 重定向
request.getRequestDispatcher("/success.jsp").forward(request,response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}