java web 02
start at 2022/10/17?

第二章 Get

开发使用eclipse,可能会有一些配置问题需要解决

创建动态web项目

新建一个dynamic web project

展开新建的web项目->展开java resources->右键src->创建Servlet窗口->java package输出controller,class name随意,父类为HTTPServlet

  • Servlet程序负责扮演控制器的角色,弗雷HTTPServlet专门用于处理HTTP请求,所有的Servlet程序一般都需要继承HTTPServlet

打开新建的文件,发现一堆函数被标红了,这是因为HTTPServlet类定义在第三方库servlet-api.jar中,所以我们需要先导入这个库

在tomcat的lib文件夹里找到这个文件,然后对着eclipse里的项目右键,选择属性,找到java构建路径,点击添加外部jar,然后找到之前lib的那个文件,点确定就可以了

package controller;

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/ABCServlet")
public class ABCServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public ABCServlet() {
        System.out.println("执行ABCServlet的构造方法");
    }

    public void init(ServletConfig config) throws ServletException {
        System.out.println("执行ABCServlet的init方法");
    }

    public void destroy() {
        System.out.println("执行ABCServlet的destroy方法");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("执行ABCServlet的doGet方法");
        System.out.println("根目录的绝对物理路径是"+request.getServletContext().getRealPath(""));
        System.out.println("执行完毕");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("执行ABCServlet的doPost方法");
    }
}

把tomcat集成到eclipse

servlet需要servler容器才能运行,tomcat提供容器,eclipse只是一个开发环境,没有提供tomcat,所以需要把第1章的tomcat集成到eclipse里

进入servers视图,单击click this link to create a new server,在新建页面里找到apache文件夹,选择tomcat v9.0,之后输入本地tomcat的文件夹路径,下一步到部署项目那里,把之前新建的项目add到configured里就可以finish了

运行服务器

右键新建的服务器,点击start,服务器就可以部署到本地了

运行第一个servlet程序

servlet程序不会自动运行,在浏览器输入servlet程序的url才会被执行,打开浏览器,访问http://localhost:8080/get/文件名前缀,然后再控制台就能看到程序的输出了

url mappings和urlPatterns

url mappings描述了服务器位置和本地文件位置的关系,上面代码中的@WebServlet("/ABCServlet")就是将浏览器地址栏url中的ABCServlet映射成ABCServlet.java的物理文件,而urlPatterns是指url mappings可以映射到多个:@WebServlet(urlPatterns={"/ABCServlet","/helloServlet"}),那么你访问这两个地址都会指向同一个程序,甚至还支持/*

servlet程序的生命周期

servlet的生命周期不同于普通的java程序,不会在运行完之后立即退出,而是一直等待,所以构建函数也只会执行一次

普通的java程序生命周期如下图

normal

而servlet程序的生命周期如下图

servlet

只有在停止服务器的时候,才会终止程序

为了提高开发效率,eclipse还提供了一种机制,eclipse能自动判断servlet源码是否被更改,如果被更改,就会重新编译并重启tomcat

创建JSP程序

在webContent目录下创建abc.jsp文件,

在该文件的<body>和</body>中间输入以下代码

<%
    System.out.println("你好,Tomcat控制台");
    String realPath = request.getServletContext().getRealPath("");
    response.getWriter().print("你好,项目部署后的绝对路径为" + realPath);
%>

如果出现乱码问题,就把文件里的ISO-8859-1编码改成UTF-8就行了

JSP和Servlet之间的关系

java web开发的核心就是Servlet程序的开发,JSP程序本质上是一个Servlet程序,当浏览器用户第一次访问JSP程序时,Tomcat服务的JSP引擎先将JSP程序翻译成Servlet源代码文件,之后就像上面Servlet程序的逻辑一样

JSP也可以视作是一个包含java的html页面,JSP更侧重与前端方面,Servlet可以视作包含html的java文件,更侧重与控制,逻辑

JSP更像是页面模板,之前用过ejs,有点类似

有关JSP的字符编码

关于JSP的编码有三个细节,第一个是JSP文件的编码形式,第二个是写在开头的pageEncoding,第三个是charset,处理这三个编码的具体逻辑是

  • 按文件编码打开JSP文件
  • JSP引擎根据pageEncoding按照指定的字符集读取JSP文件
  • charset告诉浏览器应该用什么样的编码来解析HTTP响应

当没有指定本地文件用什么样的编码储存时,eclipse会默认采用pageEncoding的编码存储,当文件中出现编码没有的字符时,eclipse就无法保存

MIME

全称Multipurpose Internet Mail Extensions,描述消息内容类型的互联网标准,语法格式为type/subtypetype大致有三类text/*,image/*,appliction/*

GET请求数据的构成

  1. GET请求行,由3部分组成,中间用空格分隔GET 请求路径?请求查询字符串 请求协议/协议版本
  2. GET请求头列表
    • Host:服务器的主机域名或IP:端口号
    • Connection:连接状态,keep-alive表示与服务器建立长久连接
    • User-Agent:发出请求浏览器的类型、版本、操作系统信息等
    • Accept:浏览器支持的MIME
    • Accept-Encoding:支持的数据压缩方式
    • Accept-Language:支持的语言种类
    • Upgrade-Insecure-Requests:浏览器是否支持自动升级请求功能
  3. 空行,一般为回车符+换行符,目的是告诉服务器请求头列表到此结束

GET全过程

  1. 在浏览器上输入URL

  2. 按下Enter键,浏览器自动将URL封装成GET请求

  3. 主机和WEB服务器建立连接,一般为TCP/IP

  4. 浏览器将封装好的GET请求发送给服务器,等待服务器响应


  1. 服务器接收到GET请求数据,将各种信息封装到HttpServletRequest请求对象中
  2. 根据GET请求行中的请求路径,Tomcat调用构造方法,创建出实例对象,调用init方法初始化实例对象
  3. 将5中封装好的请求对象传入Servlet实例对象的doGet或者doPost方法
  4. 执行方法
  5. doGet依次完成以下操作:获取HTTP请求数据;调用业务逻辑代码,处理HTTP请求数据了;将处理结果封装成HTTP响应数据
  6. 浏览器接收HTTP响应数据,显示结果,等待发起新的HTTP请求
  7. 如果一段时间内服务器和浏览器没有发生数据传输,他们之间的网络连接将会断开
  8. 服务器停止服务,调用destroy销毁

request请求对象获取GET请求数据

方法很多,主要分为六类

  1. 获取路径信息
  2. 获取GET请求参数信息
  3. 获取GET请求行信息
  4. 获取GET请求头信息
  5. 获取Web服务器主机和浏览器主机信息
  6. 获取URL Mappings
//路径信息
System.out.println(request.getContextPath());
System.out.println(request.getServletContext().getRealPath(""));
System.out.println(request.getServletContext().getRealPath("/b/c"));
System.out.println(request.getServletContext().getRealPath("/b/c/"));
System.out.println(request.getServletContext().getRealPath("b/c"));
System.out.println(request.getServletContext().getRealPath("/index.html"));
System.out.println(request.getServletContext().getRealPath("index.html"));
System.out.println(request.getRequestURI());
System.out.println(request.getRequestURL());
System.out.println(request.getServletPath());
//获取GET请求参数信息
System.out.println("获取参数名对应的值");
String name = request.getParameter("name");
String[] hobbies = request.getParameterValues("hobby");
System.out.println("你好, "+name);
System.out.println("你的兴趣爱好有:");
for(String hobby:hobbies){
    System.out.println(hobby);
}

System.out.println("获取所有参数名,输出对应参数值");
java.util.Enumeration<String> paramNames = request.getParameterNames();
while(paramNames.hasMoreElements()){
    String paramName = paramNames.nextElement();
    System.out.println(paramName);
    String[] paramValues = request.getParameterValues(paramName);
    for(String val : paramValues){
        System.out.println(val);
    }
}

System.out.println("使用Map");
java.util.Map<String,String[]>paramMap = request.getParameterMap();
for(java.util.Map.Entry<String,String[]>mapEntry: paramMap.entrySet()){
    String paramName = mapEntry.getKey();
    System.out.println("参数 "+paramName);
    String[] paramValues = request.getParameterValues(paramName);
    for(String val : paramValues){
        System.out.println(val);
    }
}
//获取GET请求行信息
System.out.println("获取"+request.getMethod()+"请求行信息");
System.out.println(request.getScheme());
System.out.println(request.getMethod());
System.out.println(request.getProtocol());
System.out.println(request.getQueryString());
System.out.println(java.net.URLEncoder.encode("张三","UTF-8"));
//获取GET请求头信息
String userAgentValue=request.getHeader("user-agent");
System.out.println("user-agent请求头的值是:"+userAgentValue);
java.util.Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
    String headerName = headerNames.nextElement();
    java.util.Enumeration<String> headerValues = request.getHeaders(headerName);
    System.out.println("请求头:"+headerName+",对应的请求头值有:");
    while(headerValues.hasMoreElements()){
        String headerValue = headerValues.nextElement();
        System.out.println(headerValue);
    }
}
//获取Web服务器主机和浏览器主机信息
System.out.println("获取web服务器主机以及浏览器主机信息");
System.out.println(request.getServerName());
System.out.println(request.getServerPort());
System.out.println(request.getLocalAddr());
System.out.println(request.getLocalPort());
System.out.println(request.getLocalName());
System.out.println(request.getRemoteAddr());
System.out.println(request.getRemotePort());
System.out.println(request.getRemoteHost());
java.util.Locale browserLocale = request.getLocale();
System.out.println(browserLocale+"*"+browserLocale.getCountry()+"*"+browserLocale.getISO3Country());
java.util.Enumeration<java.util.Locale> browserLocales = request.getLocales();
while(browserLocales.hasMoreElements()){
    java.util.Locale locale = browserLocales.nextElement();
    System.out.println(locale+"#"+locale.getCountry()+"#"+locale.getISO3Country());
}
//获取URL Mappings
System.out.println("获取URL Mappings信息");
javax.servlet.http.HttpServletMapping mapping = request.getHttpServletMapping();
String mapName = mapping.getMappingMatch().name();
String value = mapping.getMatchValue();
String pattern = mapping.getPattern();
String servletName = mapping.getServletName();
System.out.println("servlet:"+servletName);
System.out.println("URL type:"+mapName);
System.out.println("URL value:"+value);
System.out.println("URL pattern:"+pattern);

request请求对象的请求派发功能

tomcat将收到的HTTP请求数据封装在request请求对象之后,可以用RequestDispatcher,通过RequestDispatcher可以实现request请求对象的配发功能,RequestDispatcher只是一个接口,具体实现要交给Web服务软件进行

RequestDispatcher getRequestDispatcher(String path)path指向派发的目的地址,RequestDispatcher提供两种请求派发,一种是请求转发(forward),另一种是请求包含(include),下面只有请求转发的代码

转发方:

System.out.println("请求转发的基本使用");
java.util.Map<String,Object> map = new java.util.HashMap<String, Object>();
map.put("status","1");
map.put("message","登陆成功");
java.util.ArrayList<String> list = new java.util.ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
map.put("list",list);
request.setAttribute("map",map);
System.out.println("请求转发的类型是:"+request.getDispatcherType());
request.getRequestDispatcher("BCDServlet").forward(request,response);

接收方:

System.out.println("通过请求转发request请求对象读取共享的属性信息");
System.out.println("请求转发的类型是:"+request.getDispatcherType());
java.util.Map<String,Object> map = (java.util.Map<String,Object>) request.getAttribute("map");
String message = (String)map.get("message");
String status = (String)map.get("status");
java.util.ArrayList<String>list = (java.util.ArrayList<String>)map.get("list");
System.out.println("message:"+message);
System.out.println("status:"+status);
System.out.println("list:");
for(String l: list){
    System.out.println(l);
}

具体不写了,之后学到了再细学

2022/10/17
> CLICK TO back <