整体介绍

◆介绍请求与响应的结构 ◆讲解Java Web开发内置对象 ◆解决Web应用中文乱码

URL与URI

◆URL统一资源定位符,表示Web应用对外暴露的访问地址 ◆示例:http://www.imooc.com/index.html ◆URI统一资源标示符,表示Web应用资源的访问路径 ◆示例:/index.html

HTTP请求的结构

◆HTTP请求包含三部分:请求行、请求头、请求体

新建servlet工程,选择JAVA Enterprice,选择maven和junit,然后勾选上servlet组件,最后创建成功,记得在项目结构中创建web资源目录,并将web资源目录修改在src\main\webapp下,上面下面的都要修改

(69条消息) IDEA Web项目out/classes目录没有编译的class类文件 - IDEA环境下创建Maven WebApp_WalkingWithTheWind~的博客-CSDN博客

记得配置tomcat时在deployment选项卡把默认访问路径删了,因为我们只需要通过注解@websock进行url路径配置

新建java类com.imooc.servlet.RequestServlet

package com.imooc.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 RequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().println("This is get method");
    }
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().println("This is post method");
    }
}

记得extendsHttpServlet 然后映射

<servlet>
        <servlet-name>request</servlet-name>
        <servlet-class>com.imooc.servlet.RequestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>request</servlet-name>
        <url-pattern>/request</url-pattern>
    </servlet-mapping>

继续在webapp下创建request.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/request" method="post">
        <input name="username"/>
        <input name="password" type="password"/>
        <input type="submit">
    </form>
</body>
</html>

右键检查,录制网络活动,即可看到请求结构,注意使用get与post方式的区别

如何利用user-Agent进行多端应用开发?

巧用请求头开发多端应用

pc和安卓访问相同网站所呈现样式不一样,user-Agent也发生变化 继续创建UserAgentServlet.java

package com.imooc.servlet;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@WebServlet("/ua")
public class UserAgentServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String ua = request.getHeader("User-Agent");
        if(ua == null){
            response.getWriter().println("User-Agent请求头不存在");
            return;
        }
        String output = "";
        if(ua.toLowerCase().indexOf("windows nt") != -1){
            output = "<h1>这是PC端页面</h1>";
        }else if(ua.toLowerCase().indexOf("iphone") != -1 || ua.toLowerCase().indexOf("android") != -1){
            output = "<h1>这是移动端页面</h1>";
        }
 
        response.getWriter().println(output);
    }
}

使用注解@WebServlet("/ua")简化映射配置 http://localhost:8080/ua 即可访问

toLowerCase()转小写 response.setContentType("text/html;charset=utf-8");防止中文乱码

HTTP响应的结构

◆HTTP响应包含三部分:响应行、响应头、响应体

HTTP常见响应状态码

ContentType的作用

◆ContentType决定浏览器采用何种方式对响应体进行处理

servlet包下新建ContentTypeServlet.java

package com.imooc.servlet;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@WebServlet("/ct")
public class ContentTypeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String output = "<h1><a href='http://www.baidu.com'><span>百度</span></a></h1>";
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println(output);
    }
}

若改为text/plain,则直接将代码打印出来,改为text/xml,则以xml格式打印出来 charset=utf-8表示强制使用utf-8对其中中文处理,就不会产生乱码问题了

请求转发与响应重定向

上面都是单个servlet请求与处理,但在项目中会存在servlet之间信息传递工作 ◆多个Servlet之间跳转有两种方式: ◆request.getRequestDispatcher().forward()-请求转发 ◆response.sendRedirect()-响应重定向

比如网站首页和登陆界面之间的跳转 新建java类com.imooc.servlet.forward,新建CheckLoginServlet.java

package com.imooc.servlet.forward;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
 
@WebServlet("/login")
public class CheckLoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if(username.equals("admin") && password.equals("123456")){
            System.out.println("用户登录成功");
            //request.setAttribute("username",username);
            //请求转发
            //request.getRequestDispatcher("/index").forward(request,response);
            HttpSession session = request.getSession();
            session.setAttribute("username",username);
            //响应重定向
            response.sendRedirect("/index");
        }else{
            System.out.println("用户登录失败");
        }
    }
}

新建登陆页面html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login" method="post">
        <input name="username">
        <input name="password" type="password">
        <input type="submit">
    </form>
</body>
</html>

继续新建首页IndexServlet.java

package com.imooc.servlet.forward;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
 
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //String username = (String)request.getAttribute("username");
        HttpSession session = request.getSession();
        String username = (String)session.getAttribute("username");
        response.getWriter().println("我是MK网首页,当前用户:" + username);
    }
}

首页html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>我是默认首页</h1>
</body>
</html>

登陆界面重写dopost方法,首页界面也要重写dopost方法 请求转发后url不变,不需要doget方法,响应重定向url改变,需要doget方法,需要产生两次交互,异常交给login,一次交给index

为何需要这两种方式,有什么区别

请求转发

◆请求转发是服务器跳转,只会产生一次请求 ◆请求转发语句是:request.getRequestDispatcher().forward()

  1. url链接不变,不跳转
  2. 方法一致

响应重定向

◆重定向则是浏览器端跳转,会产生两次请求 ◆响应重定向语句是:response.sendRedirect()

响应重定向产生的新请求方式默认使用get方式

适用于跳转第三方网站

设置请求自定义属性

◆请求允许创建自定义属性 ◆设置请求属性:request.setAttribute(属性名,属性值) ◆获取请求属性:Object attr=request.getAttribute(属性名) 在login获取用户名 request.setAttribute("username",username); 在index得到用户名 String username = (String)session.getAttribute("username"); username生命周期与request一致,当改为使用响应重定向时,新的响应请求已经销毁request对象,所以用户名为null,适用于请求转发 如果想要重定向也能处理,需要使用范围更大的session对象

浏览器Cookie

◆Cookie(小甜饼)是浏览器保存在本地的文本内容 ◆Cookie常用于保存登录状态、用户资料等小文本 ◆Cookie具有时效性,Cookie内容会伴随请求发送给Tomcat

自动登录选项通过本地cookie即使退出浏览器也保持登陆状态 新建子包cookie 新建RandomServlet.java文件生成随机cookie值

package com.imooc.servlet.cookie;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Random;
 
@WebServlet("/cookie/random")
public class RandomServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Integer random = new Random().nextInt(10000);
        Cookie cookie = new Cookie("random" , String.valueOf(random));
        cookie.setMaxAge(60*60*24);
        response.addCookie(cookie);
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("<h2>随机数" +  random+ "已生成</h2>");
    }
}

cookie.setMaxAge(606024);设置cookie有效期为一天,当关闭浏览器重新访问url时,可以继续访问

新建CookieServlet.java获取cookie

package com.imooc.servlet.cookie;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@WebServlet("/cookie/show")
public class CookieServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        Integer random = -1;
        response.setContentType("text/html;charset=utf-8");
        if(cookies == null){
            response.getWriter().println("未包含任何Cookie数据");
            return;
        }
        for (Cookie c : cookies){
            if(c.getName().equals("random")){
                random = Integer.parseInt(c.getValue());
            }
        }
 
        response.getWriter().println("name=random的cookie值为:" + random);
    }
}

访问http://localhost:8080/cookie/show

用户会话Session

防止cookie泄露,使用Session提高安全性 ◆Session(用户会话)用于保存与“浏览器窗口”对应的数据 ◆Session的数据存储在Tomcat服务器的内存中,具有时效性 ◆Session通过浏览器Cookie的Sessionld值提取用户数据

通过cookie的Sessionld找到tomcat的内存,存入cookie

Session常用方法

◆request.getSession()-获取Session对象 ◆getsetremoveAttribute()-获取设置删除Session属性 ◆setMaxlnactivelnterval()-设置Session超时时间

新建子包session 新建RandomServlet.java随机生成cookie

package com.imooc.servlet.session;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Random;
 
@WebServlet("/session/random")
public class RandomServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Integer random = new Random().nextInt(10000);
        HttpSession session = request.getSession();
        session.setAttribute("random" , random);
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("<h2>随机数" +  random + "已生成</h2>");
    }
}

新建Seseion提取cookie

package com.imooc.servlet.session;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
 
@WebServlet("/session/show")
public class SessionServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        Integer random = (Integer)session.getAttribute("random");
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("name=random的session值为:" + random);
    }
}

Session的原理

不小心关闭浏览器窗口,在未到达存储周期30分钟前,sessionId与窗口绑定,cookie不存在了,用户本地没了sessionId,服务器会重新寻找一块sessionld,而浏览器关闭后,cookie消失,服务器sessionId存在,要30分钟后才销毁,再次打开根据SessionId得到cookie,存储周期后这块区域才会销毁

第一个请求是往Tomcat放数,第二个响应是从Tomcat取数

当点击网页下不同分栏是,登录信息不会改变,都会被提取出来,使用的是session方案 详细查看请求转发与网页重定向那一节,切换到新标签也能得到登陆信息

ServletContext与三大作用域对象

ServletContext

期望有个全局存储空间,不需要每次打开网页就从数据库重新读取,即使浏览器关闭也能提取出来,比如网站备案信息

◆ServletContext(Servlet_上下文对象),是Web应用全局对象 ◆ー个WebServletContext对象 ◆ServletContext随着Web应用启动而自动创建

新建ServletContextinitServlet.java文件

package com.imooc.servlet.servletcontext;
 
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@WebServlet("/servletcontext/init")
public class ServletContextInitServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = request.getServletContext();
        servletContext.setAttribute("copyright", "Copyright© 2021 imooc.com  京ICP备 12003892号-11 京公网安备11010802030151号");
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("ServletContext已初始化");
 
    }
}

在创建一个网页IndexServlet.java

package com.imooc.servlet.servletcontext;
 
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
 
@WebServlet("/servletcontext/index")
public class IndexServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        ServletContext context = request.getServletContext();
        String copyright = (String)context.getAttribute("copyright");
        PrintWriter out = response.getWriter();
        out.println("导航栏");
        out.println("<hr/>");
        out.println("首页正文");
        out.println("<hr/>");
        out.println(copyright);
    }
}

Java Web三大作用域对象

◆HttpServletRequest-请求对象 ◆HttpSession-用户会话对象 ◆ServletContext-Web应用全局对象

Web应用的中文乱码由来

◆发送方与接收方对数据使用不同的字符集解析就会产生乱码 ◆解决乱码的思路是保证浏览器与服务器统一为UTF-8编码即可 ◆在Servlet中请求与响应都需要设置UTF-8字符集

webapp下新建search.html

<!DOCTYPE html>
<html lang="en">
<head>
    <!--浏览器发送请求时使用的字符集编码-->
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/encoding/search" method="post">
        <input name="keyword"/>
        <input type="submit"/>
    </form>
</body>
</html>

在新建java处理SearchServlet.java

package com.imooc.servlet.encoding;
 
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@WebServlet("/encoding/search")
public class SearchServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //在Tomcat 8以后,默认对GET请求发来的参数视为UTF-8编码进行解析
        //在Tomcat 8以前,默认为ISO-8859-1,需要在server.xml配置字符集
        String keyword = request.getParameter("keyword");
        System.out.println(keyword);
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println(keyword);
    }
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //利用UTF-8编码解析请求体中的请求参数
        request.setCharacterEncoding("UTF-8");
        String keyword = request.getParameter("keyword");
        System.out.println(keyword);
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println(keyword);
    }
}

(69条消息) 设置Tomcat字符集为utf-8_皓月如我的博客-CSDN博客 注意doGet与doPost处理乱码方式不一样

web.xml常用配置

◆修改web应用默认首页 ◆Servlet通配符映射及初始化参数 ◆设置404、500等状态码默认页面

但没有输入任何URI时,会跳到首页,而不是404 在webapp下新建index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>我是默认首页</h1>
</body>
</html>

web.xml配置

<welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>default.html</welcome-file>
    </welcome-file-list>

不存在index.html,就会使用default.html

常见的URL用法

http://www.imooc.com/search?cid=785 http://www.imooc.com/class/785 http://www.imooc.com/785.class

我们不用注解配置,而使用xml配置,因为需要配置的多,后期便于维护

新建PatternServlet.java

package com.imooc.servlet;
 
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 PatternServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*if(1==1){
            throw new RuntimeException("未知错误");
        }*/
        String uri = request.getRequestURI();// URI:/class/785
//        只需要785这几个数字  +1表示不包括’/‘
        String id = uri.substring(uri.lastIndexOf("/") + 1);
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("<h1>");
        if(id.equals("785")){
            out.println("Vue3.0高阶实战");
        }else if(id.equals("786")){
            out.println("面霸修炼手册");
        }else{
            out.println("其他课程");
        }
        out.println("</h1>");
    }
}

通过修改785,786控制不同网页访问 记得进行xml配置

<servlet>
        <servlet-name>pattern</servlet-name>
        <servlet-class>com.imooc.servlet.PatternServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>pattern</servlet-name>
        <!--http://www.imooc.com/class/785-->
        <url-pattern>/class/*</url-pattern>
    </servlet-mapping>

<url-pattern>/class/*</url-pattern>为通配符 我们可以对一个Servlet进行多个映射,可以添加

<servlet-name>pattern</servlet-name>
        //http://www.imooc.com/785.class
        <url-pattern>*.class</url-pattern>
    </servlet-mapping>

注意,前缀加后缀的混合应用是不支持的的 比如下面代码

<servlet-mapping>
        <servlet-name>pattern</servlet-name>
        //http://www.imooc.com/class/785.class
        <url-pattern>/class/*.class</url-pattern>
    </servlet-mapping>

有一个特殊写法,对所有请求进行映射

<servlet-mapping>
        <servlet-name>pattern</servlet-name>
        &lt;!&ndash; 对所有请求进行映射,Spring MVC框架中会使用到这个特性
        <url-pattern>/</url-pattern>
    </servlet-mapping>-->

启动时加载Servlet与错误页面设置

启动时加载Servlet

◆web.xml使用<load-on-startup>设置启动加载 ◆<load-on-startup>0~9999</load-on-startup> ◆启动时加载在工作中常用于系统的预处理

设置错误页面

tomcat默认提供的页面会暴露很多信息,导致受到攻击,所以一般会自己设置错误页面 webapp下新建目录error 新建404界面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    抱歉,您访问的页面不存在!
</body>
</html>

替换掉404,在web.xml文件中

<error-page>
        <error-code>404</error-code>
        <location>/error/404.html</location>
    </error-page>

JavaWeb打包与发布

◆Java Web应用采用war包进行发布 ◆发布路径为:{TOMCAT HOME}/webapps ◆利用Maven实现war包导出

打包war包,核心在pom.xml中添加配置

<packaging>war</packaging>

修改war包名

<build>
        <finalName>web-servlet</finalName>
    </build>

然后运行右侧Maven栏package命令,如何不配置,打包的是jar包

target目录下可以看到war包存在 war包用压缩软件打开,是javaweb的标准工程

<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

添加<scope>provided</scope>再次生成war包,解压缩,发现WEB-INF下的lib目录不见了,说明3.1.0的javax.servlet并没有打包进来,我们这样做的原因是tomcat的lib目录自带了servlet-api.jar包

Maven的Scope属性

最后只要把war包复制在tomcat的webapps目录下即可 然后点击bin目录下startup.bat,war包就被自动解压缩了,可以直接在浏览器访问了,但是注意需要添加上URI即文件夹名/web-servlet/

此时出现一个问题,当网页跳转时会把URI给去掉(我们开发时没有使用web-servlet),会导致404,这是需要在tomcat的conf文件夹下对server.xml进行配置 在Host标签下书写<Context docBase="web-servlet" path="/" />即将上下文路径设置为默认的’/‘,这里的’/‘是我们开发时在tomcat运行配置界面自己设置的,所以就要和开发时设置的一样