java-web6-Servlet知识

6.Servlet

6.1 Servlet简介
  • Servlet是sun公司开发的一门动态web技术
  • sun在api中提供了一个接口:Servlet。开发需要实现此接口,并将其部署到web服务器中
  • 总结:实现了Servlet接口的java程序叫Servlet
6.2 简单Servlet创建
  • Servlet接口有两个实现类GenericServlet,HttpServlet

  • Servlet接口

void init(ServletConfig var1) throws ServletException;

void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

void destroy();
  • GenericServlet类
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
  • HttpServlet实现了service方法,但需要自己是实现

构建一个普通maven项目,删掉src目录,在这个项目中建moduel,此项目为maven主工程

在这里插入图片描述

maven父子工程描述:父项目中有子项目关联

<modules>
    <module>servlet-01</module>
</modules>
  • 子项目中父项目关联
<parent>
    <artifactId>web03</artifactId>
    <groupId>com.zk</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
  • 父项目中jar子项目可以直接使用,继承多态的概念

maven环境友好

  • 修改web.xml为最新配置
  • 将maven项目结构搭建完整

编写serlet程序

  • 实现servelt接口,直接继承HttpServlet
//get和post是不同的请求方式,可以互相调用
/* ServletInputStream inputStream = req.getInputStream();
 BufferedReader reader = req.getReader();
 ServletOutputStream outputStream = resp.getOutputStream();*/
 PrintWriter writer = resp.getWriter();
 writer.println("hello world!");

编写 Servlet映射

  • 为什么需要:java程序有浏览器访问,浏览器链接web服务器,需要在web服务中注册servlet,需要个浏览器能访问的路径
<!--注册servlet-->
<servlet>
    <servlet-name>helloS</servlet-name>
    <servlet-class>com.zk.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
    <servlet-name>helloS</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

配置tomcat:配置项目发布的路径

启动测试

6.3 Servlet原理
  • web服务器和web容器不是一个东西
  • Servlet由web服务器调用,web服务器收到浏览器请求后会:
  • web容器调用Service方法把这两个对象Request对象、Response对象传入该service方法,将Request对象到该service方法的实现类去处理,返回Response对象让容器获取,容器将Response返回给浏览器。
    在这里插入图片描述
6.4 mappint映射问题
  • 一个servlet可以指定一个映射路径
<!--注册servlet-->
<servlet>
    <servlet-name>helloS</servlet-name>
    <servlet-class>com.zk.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
    <servlet-name>helloS</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>
  • 一个servlet可以指定多个映射路径
<!--注册servlet-->
<servlet>
    <servlet-name>helloS</servlet-name>
    <servlet-class>com.zk.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
    <servlet-name>helloS</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>helloS</servlet-name>
    <url-pattern>/hello2</url-pattern>
</servlet-mapping>
  • 一个servlet可以指定通用映射路径,
<servlet-mapping>
    <servlet-name>helloS</servlet-name>
    <url-pattern>/hel/*</url-pattern>
</servlet-mapping>
  • 默认请求路径,/*会优先于index.jsp进入servlet(尽量少用)
<servlet-mapping>
    <servlet-name>helloS</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
  • 一个servlet可以指定前缀或后缀映射路径
<!--/*.do报错,不能加项目映射路径/
v1/s2.do-->
<servlet-mapping>
    <servlet-name>helloS</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>
  • 优先级问题:指定了固定映射路径的优先级最高,找不到找默认的处理请求
<servlet>
    <servlet-name>error</servlet-name>
    <servlet-class>com.zk.servlet.ErrorServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
    <servlet-name>error</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
6.5 ServletContext
  • web容器启动时,会为每个web程序创建一个ServletContext对象,代表了当前web应用
this.getInitParameter(""); //获得参数信息
ServletConfig servletConfig = this.getServletConfig();//ServletConfig 配置
ServletContext servletContext = this.getServletContext();  //ServletContext上下文
<!--全局参数-->
<!--<context-param>
    <param-name></param-name>
    <param-value></param-value>
</context-param>-->
<servlet>
        <servlet-name>testS</servlet-name>
        <servlet-class>com.zk.servlet.TestServlet</servlet-class>
        <!--携带参数-->
        <!--<init-param>
            <param-name></param-name>
            <param-value></param-value>
        </init-param>-->
    </servlet>
  • 设置响应编码
resp.setContentType("text/html;charset=utf-8");
6.5.1 共享数据:某个servlet保存数据,另一个servlet中拿到
  • 存放ServletContext类
public class TestServlet   extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("进入get方法!");
        this.getInitParameter(""); //获得参数信息
        ServletConfig servletConfig = this.getServletConfig();//ServletConfig 配置
        ServletContext servletContext = this.getServletContext();  //ServletContext上下文
        String name = "托尼";
        servletContext.setAttribute("name",name);
    }
  • 获取ServletContext中值
public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = (String)this.getServletContext().getAttribute("name");
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().println("参数:"+name);
    }
  • web.xml中映射配置
<servlet>
    <servlet-name>testS</servlet-name>
    <servlet-class>com.zk.servlet.TestServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
    <servlet-name>testS</servlet-name>
    <url-pattern>/test</url-pattern>
</servlet-mapping>
<servlet>
    <servlet-name>getS</servlet-name>
    <servlet-class>com.zk.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>getS</servlet-name>
    <url-pattern>/getS</url-pattern>
</servlet-mapping>
  • 启动测试。
6.5.2 存在问题
  • 方式1:idea控制台启动tomcat时显示乱码问题:1.需要在tomcat文件conf设置
apache-tomcat-8.5.41\conf\logging.properties
java.util.logging.ConsoleHandler.encoding = GBK
  • 方式2:idea控制台启动tomcat时显示乱码问题:2.help里有个VM选项idea64.exe.vmoptions。在里面加上-Dfile.encoding=UTF-8
    在这里插入图片描述
    在这里插入图片描述
    idea设置文件编码步骤:File——>Settings——>Editor——>File Encodings,将三处编码格式改为UTF-8
    在这里插入图片描述
  • 重要的一步:服务器vm设置-Dfile.encoding=UTF-8
    在这里插入图片描述
  • 重新启动服务器,乱码纠正。
6.5.3 获取初始化参数
  • web.xml中配置全局初始化参数
<context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost/mybatis</param-value>
</context-param>
  • 创建servlet获取参数
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("utf-8");
    resp.setContentType("text/html;charset=utf-8");
    ServletContext servletContext = this.getServletContext();
    String url = servletContext.getInitParameter("url");
    resp.getWriter().println("参数:"+url);
}
  • 配置路径映射
<servlet>
    <servlet-name>sd01</servlet-name>
    <servlet-class>com.zk.servlet.ServletDemo01</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>sd01</servlet-name>
    <url-pattern>/sd01</url-pattern>
</servlet-mapping>
6.5.4 请求转发
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("utf-8");
    resp.setContentType("text/html;charset=utf-8");
    ServletContext servletContext = this.getServletContext();
    RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/sd01"); //转发请求路径
    requestDispatcher.forward(req,resp);  //调用forward实现请求转发
}
  • 转发:请求路径不变
  • 重定向:请求路径发生变化
6.5.5 读取资源文件
  • Properties:在java目录下新建properties文件;在resources目录下新建properties文件
  • 都配打包到同一路径下,classes(类路径),叫classpath
  • 通过ServletContext中的资源转流对象加载properties文件
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("utf-8");
    resp.setContentType("text/html;charset=utf-8");
    ServletContext servletContext = this.getServletContext();
    /*"/为当前web项目*/
    InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/com/zk/servlet/test.properties");
    Properties prop = new Properties();
    prop.load(is);
    String username = prop.getProperty("username");
    String password = prop.getProperty("password");
    resp.getWriter().println(username+"::"+password);
}
username=root
password=123456123456
#classpath类路径:target下的class路径=源码中的java和resource文件


  • 进行访问测试
root::123456123456
6.6 HttpServletRequest
  • HttpServletRequest代表客户端请求,用户通过http协议访问服务器,http请求中所有信息会封装到HttpServletRequest对象中,通过此对象的方法获得客户端请求的所有信息。
6.6.1 获取前端传递的参数

在这里插入图片描述

6.6.2 请求转发
  • 请求转发映射的地址是localhost:8080/当前web目录,而重定向映射的地址是localhost:8080
  • HttpServletRequest请求转发时,页面jsp里面就已经获取了/r传过来的
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//处理请求
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] loves = req.getParameterValues("love");
req.getSession().setAttribute("username",username);
req.getSession().setAttribute("password",password);
System.out.println(username+":"+password);
System.out.println(Arrays.toString(loves));
//重定向时注意路径问题,否则会出现404
//resp.sendRedirect("/s2/success.jsp");
//这个/代表web应用
req.getRequestDispatcher("/success.jsp").forward(req,resp);
6.7 HttpServletResponse
  • web服务器接收到客户端的http请求,针对这个请求,分别创建一个请求对象HttpServletRequest,和一个响应对象HttpServletResponse
  • 获取客户端请求的参数用:HttpServletRequest
  • 给客户端响应信息用:HttpServletResponse
6.7.1 分类
  • 负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;//其他流,否则用PrintWriter导致字符串丢失

PrintWriter getWriter() throws IOException;  //中文流
  • 负责向浏览器发送响应头的方法
void setCharacterEncoding(String var1);

void setContentLength(int var1);

void setContentLengthLong(long var1);

void setContentType(String 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);

  • 响应的状态码
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;
6.7.2 常见应用
  • 向浏览器输出信息
  • 下载文件

获取下载文件的路径

下载的文件名是什么

设置浏览器支持下载的内容

获取下载文件输入流

创建缓冲区

获取OutputStream对象

将FileOutputStream流写入到buffer缓冲区

使用OutputStream将缓冲区中的数据输出到客户端

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("comeing fileServlet!");
    req.setCharacterEncoding("utf-8");
    resp.setContentType("text/html;charset=utf-8");
    ServletContext servletContext = this.getServletContext();
    //String realPath = servletContext.getRealPath("/WEB-INF/classes/可达鸭.png");
    String realPath = servletContext.getClassLoader().getResource("/可达鸭.png").getPath().replace("%20", " ");
    System.out.println(realPath);
    String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
    //web下载文件的头部
    System.out.println("realPath========"+realPath);
    //D:\apache-tomcat-8.5.41\apache-tomcat-8.5.41\webapps\s2\可达鸭.png 无此图片
    //URLEncoder.encode(fileName,"utf-8")对中文进行编码否则会乱码
    resp.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));
    FileInputStream fis = new FileInputStream(realPath);
    ServletOutputStream os = resp.getOutputStream();
    int len = 0;
    byte[] bytes = new byte[1024];
    while ((len=fis.read(bytes))!=-1){
        os.write(bytes,0,len);
    }
    os.close();
    fis.close();
}
6.7.3 验证码功能
  • 前端实现
  • 后端实现,要用java图片类,产生一个图片
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //让浏览器4秒刷新一次
    resp.setHeader("refresh","4");
    //内存中创建一张图片
    BufferedImage bi = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
    //得到画笔
    Graphics g = bi.getGraphics();
    //设置背景色
    g.setColor(Color.white);
    g.fillRect(0,0,80,20);
    //给图片写数据
    g.setColor(Color.cyan);
    g.setFont(new Font(null,Font.ITALIC,20));

    g.drawString(getRandom(),0,20);

    //给浏览器设置响应格式
    resp.setContentType("image/jpeg");
    //设置浏览器不缓存
    resp.setDateHeader("expires",-1);
    resp.setHeader("Cache-Control","no-cache" );
    resp.setHeader("Pragma","no-cache");
    ImageIO.write(bi, "jpg", resp.getOutputStream());
}
public static String getRandom(){
    Random random = new Random();
    String num = String.valueOf(random.nextInt(9999));
    StringBuffer stringBuffer = new StringBuffer();
    for (int i = 0; i < 4-num.length(); i++) {
        stringBuffer.append("0");
    }
    return  stringBuffer.toString() + num;
}
6.7.4 HttpServletResponse重定向
  • 一个web资源B收到A请求后,B会通知A去访问另一个web资源C,此过程成为重定向
  • 场景:用户登录
void sendRedirect(String var1) throws IOException;
  • 重定向因为可能会跳转到不是该web项目下的链接,所以不自动加上下文是正常的
resp.sendRedirect("/s2/is");
//等效
/*resp.setHeader("Location","/s2/is");
resp.setStatus(HttpServletResponse.SC_FOUND);*/
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        //处理请求
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        req.getSession().setAttribute("username",username);
        req.getSession().setAttribute("password",password);
        System.out.println(username+":"+password);
        //重定向时注意路径问题,否则会出现404
        resp.sendRedirect("/s2/success.jsp");

    }
<%--login.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h2>Hello World!</h2>
<%--${pageContext.request.contextPath}当前项目路径--%>
<form action="<%=this.getServletConfig().getServletContext().getContextPath()%>/login" method="get">
    账号:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" name="提交">
</form>
</body>
</html>
<%--success.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>success</title>
</head>
<body>
<h2>主页面</h2>
username:<%=session.getAttribute("username")%><br>
password:<%=session.getAttribute("password")%><br>
</body>
</html>
6.8 转发和重定向区别

相同点

  • 页面都会实现跳转

不同点

  • 转发时,请求路径不改变,请求转发是内部跳转;307
  • 重定向,请求路径改变;302
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值