Servlet(一)

简介: 关于Servlet的相关介绍

①.Web概述

1. web概念概述

JavaWeb:使用Java语言开发基于互联网的项目

软件架构:

1. C/S: Client/Server 客户端/服务器端

* 在用户本地有一个客户端程序,在远程有一个服务器端程序

* 如:QQ,迅雷...

* 优点:

 1. 用户体验好

 2. 安全性比较好

* 缺点:

 1. 开发、安装,部署,维护 麻烦

2. B/S: Browser/Server 浏览器/服务器端

* 只需要一个浏览器,用户通过不同的网址(URL),客户访问不同的服务器端程序

* 优点:

 1. 开发、安装,部署,维护 简单

* 缺点:

 1. 如果应用过大,用户的体验可能会受到影响

 2. 安全性较差

20190810112201309.png

20190810122354273.png

20190812204608628.png

2.web服务器软件

  • 服务器:安装了服务器软件的计算机
  • 服务器软件:接收用户的请求,处理请求,做出响应
  • web服务器软件:接收用户的请求,处理请求,做出响应。

在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目web容器

20190810123226100.png

②.Tomcat

1. Tomcat:web服务器软件


1. 下载:http://tomcat.apache.org/

2. 安装:解压压缩包即可。

* 注意:安装目录建议不要有中文和空格

3. 卸载:删除目录就行了

4. 启动:

* bin/startup.bat ,双击运行该文件即可

* 访问:浏览器输入:http://localhost:8080 回车访问自己

      http://别人的ip:8080 访问别人


20190810130653417.png


2. tomcat启动问题分析


一般tomcat的默认端口号是:8080


Http默认的端口号是:80

* 可能遇到的问题:
1. 黑窗口一闪而过:
  * 原因: 没有正确配置JAVA_HOME环境变量
  * 解决方案:正确配置JAVA_HOME环境变量
2. 启动报错:
  1. 暴力:找到占用的端口号,并且找到对应的进程,杀死该进程
  * netstat -ano
  2. 温柔:修改自身的端口号
  * conf/server.xml
  * <Connector port="8888" protocol="HTTP/1.1"
              connectionTimeout="20000"
              redirectPort="8445" />
  * 一般会将tomcat的默认端口号修改为80。80端口号是http协议的默认端口号。
    * 好处:在访问时,就不用输入端口号

20190810125128606.png20190810130241282.png20190818100959891.png


3. tomcat 的关闭


①.正常关闭:(1).bin/shutdown.bat (2) ctrl+c [ 推荐 ]


②.强制关闭:点击启动窗口的×


4. 部署项目方式

* 部署项目的方式:
  1. 直接将项目放到webapps目录下即可。
  * /hello:项目的访问路径-->虚拟目录
  * 简化部署:将项目打成一个war包,再将war包放置到webapps目录下。
    * war包会自动解压缩
  2. 配置conf/server.xml文件
  在<Host>标签体中配置
  <Context docBase="D:\hello" path="/hehe" />
  * docBase:项目存放的路径
  * path:虚拟目录
  3. 在conf\Catalina\localhost创建任意名称的xml文件。在文件中编写
  <Context docBase="D:\hello" />
  * 虚拟目录:xml文件的名称[浏览器访问的地址]



5. 静态目录和动态目录


20190813222735711.png2019081322365613.png


//访问首页
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

20190810141920131.png

6. Tomcat的目录结构 [ 重点 ]

2019081221221654.png



(1)bin:该目录下存放的是二进制可执行文件,如果是安装版,那么这个目录下会有两个exe文件:tomcat6.exe、tomcat6w.exe,前者是在控制台下启动Tomcat,后者是弹出UGI窗口启动Tomcat;如果是解压版,那么会有startup.bat和shutdown.bat文件,startup.bat用来启动Tomcat,但需要先配置JAVA_HOME环境变量才能启动,shutdawn.bat用来停止Tomcat;


(2)conf:这是一个非常非常重要的目录,这个目录下有四个最为重要的文件:

a. server.xml:配置整个服务器信息。例如修改端口号,添加虚拟主机等;下面会详细介绍这个文件;


b. tomcatusers.xml:存储tomcat用户的文件,这里保存的是tomcat的用户名及密码,以及用户的角色信息。可以按着该文件中的注释信息添加tomcat用户,然后就可以在Tomcat主页中进入Tomcat Manager页面了;


c. web.xml:部署描述符文件,这个文件中注册了很多MIME类型,即文档类型。这些MIME类型是客户端与服务器之间说明文档类型的,如用户请求一个html网页,那么服务器还会告诉客户端浏览器响应的文档是text/html类型的,这就是一个MIME类型。客户端浏览器通过这个MIME类型就知道如何处理它了。当然是在浏览器中显示这个html文件了。但如果服务器响应的是一个exe文件,那么浏览器就不可能显示它,而是应该弹出下载窗口才对。MIME就是用来说明文档的内容是什么类型的!


d. context.xml:对所有应用的统一配置,通常我们不会去配置它。


(3)lib:Tomcat的类库,里面是一大堆jar文件。如果需要添加Tomcat依赖的jar文件,可以把它放到这个目录中,当然也可以把应用依赖的jar文件放到这个目录中,这个目录中的jar所有项目都可以共享之,但这样你的应用放到其他Tomcat下时就不能再共享这个目录下的Jar包了,所以建议只把Tomcat需要的Jar包放到这个目录下;


(4)logs:这个目录中都是日志文件,记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,那么异常也会记录在日志文件中。


(5)temp:存放Tomcat的临时文件,这个目录下的东西可以在停止Tomcat后删除!


(6)webapps:存放web项目的目录,其中每个文件夹都是一个项目;如果这个目录下已经存在了目录,那么都是tomcat自带的。项目。其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。http://localhost:8080/examples,进入示例项目。其中examples就是项目名,即文件夹的名字。


(7)work:运行时生成的文件,最终运行的文件都在这里。通过webapps中的项目生成的!可以把这个目录下的内容删除,再次运行时会生再次生成work目录。当客户端用户访问一个JSP文件时,Tomcat会通过JSP生成Java文件,然后再编译Java文件生成class文件,生成的java和class文件都会存放到这个目录下。


(8)LICENSE:许可证。


(9)NOTICE:说明文件。


③. Servlet


1. servlet 基础知识

20190812192748168.png


1>.什么是Servlet


Servlet是JavaWeb的三大组件之一,它属于动态资源。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要:

①. 接收请求数据;②. 处理请求;③. 完成响应


2>. 实现Servlet的方式(由我们自己来写!)


实现javax.servlet.Servlet接口;


继承javax.servlet.GenericServlet类[ 这是一个抽象类, 父类是Servlet ];


继承javax.servlet.http.HttpServlet类 [ 父类是GenericServlet ];


通常我们会去继承HttpServlet类来完成我们的Servlet,但学习Servlet还要从javax.servlet.Servlet接口开始学习。

2. Servlet


1>. Servlet的源码分析


2019081022271631.png

执行原理:
  1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
  2. 查找web.xml文件,是否有对应的<url-pattern>标签体内容。
  3. 如果有,则在找到对应的<servlet-class>全类名
  4. tomcat会将字节码文件加载进内存,并且创建其对象

20190819231832464.png

2>. Servlet的生命周期


所谓xxx的生命周期,就是说xxx的出生、服务,以及死亡。Servlet生命周期也是如此!与Servlet的生命周期相关的方法有:


①. void init(ServletConfig config);


②. void service(ServletRequest,ServletResponse);


③. void destroy();


(1)servlet的出生

服务器会在Servlet第一次被访问时创建Servlet,或者是在服务器启动时创建Servlet。如果服务器启动时就创建Servlet,那么还需要在web.xml文件中配置。也就是说默认情况下,Servlet是在第一次被访问时由服务器创建的。


而且一个Servlet类型,服务器只创建一个实例对象,例如在我们首次访问时,服务器通过“/helloworld”找到了绑定的Servlet名称为cn.itcast.servlet.HelloServlet,然后服务器查看这个类型的Servlet是否已经创建过,如果没有创建过,那么服务器才会通过反射来创建HelloServlet的实例。当我们再次访问时,服务器就不会再次创建HelloServlet实例了,而是直接使用上次创建的实例。


在Servlet被创建后,服务器会马上调用Servlet的void init(ServletConfig)方法。请记住, Servlet出生后马上就会调用init()方法,而且一个Servlet的一生。这个方法只会被调用一次。这好比小孩子出生后马上就要去剪脐带一样,而且剪脐带一生只有一次。

我们可以把一些对Servlet的初始化工作放到init方法中!


(2)Servlet服务


当服务器每次接收到请求时,都会去调用Servlet的service()方法来处理请求。服务器接收到一次请求,就会调用service() 方法一次,所以service()方法是会被调用多次的。正因为如此,所以我们才需要把处理请求的代码写到service()方法中!


(3)Servlet的离去


Servlet是不会轻易离去的,通常都是在服务器关闭时Servlet才会离去!在服务器被关闭时,服务器会去销毁Servlet,在销毁Servlet之前服务器会先去调用Servlet的destroy()方法,我们可以把Servlet的临终遗言放到destroy()方法中,例如对某些资源的释放等代码放到destroy()方法中。


在首次访问HelloServlet时,init方法会被执行,而且也会执行service方法。再次访问时,只会执行service方法,不再执行init方法。在关闭Tomcat时会调用destroy方法

20190810224053208.png


3>. ServletConfig


ServletConfig对象对应web.xml文件中的元素。例如你想获取当前Servlet在web.xml文件中的配置名,那么可以使用servletConfig.getServletName()方法获取!


String getServletName():获取Servlet在web.xml文件中的配置名称,即指定的名称;


ServletContext getServletContext():用来获取ServletContext对象,ServletContext会在后面讲解;


String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;


20190810224614156.png


20190810224749723.png


3. GenericServlet(抽象类)


将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象;将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可


1>. GenericServlet类的源码分析


GenericServlet是Servlet接口的实现类,我们可以通过继承GenericServlet来编写自己的Servlet。下面是GenericServlet类的源代码20190810225127953.png



2>. GenericServlet的init( )方法


①. 在GenericServlet中,定义了一个ServletConfig config实例变量,并在init(ServletConfig)方法中把参数ServletConfig赋给了实例变量。然后在该类的很多方法中使用了实例变量config


②. 如果子类覆盖了GenericServlet的init(StringConfig)方法,那么this.config=config这一条语句就会被覆盖了,也就是说GenericServlet的实例变量config的值为null,那么所有依赖config的方法都不能使用了。如果真的希望完成一些初始化操作,那么去覆盖GenericServlet提供的init()方法,它是没有参数的init()方法,它会在init(ServletConfig)方法中被调用


3>. 实现了ServletConfig接口


GenericServlet还实现了ServletConfig接口,所以可以直接调用getInitParameter()、getServletContext()等ServletConfig的方法。

4. HttpServlet [ 掌握 ]


1>. HttpServlet概述


HttpServlet类是GenericServlet的子类,它提供了对HTTP请求的特殊支持,所以通常我们都会通过继承HttpServlet来完成自定义的Servlet。


(1) HttpServlet类中提供了service(HttpServletRequest,HttpServletResponse)方法,

这个方法是HttpServlet自己的方法,不是从Servlet继承来的。在HttpServlet的

service(ServletRequest,ServletResponse)方法中会把ServletRequest和ServletResponse强转成HttpServletRequest和HttpServletResponse,然后调用service(HttpServletRequest,HttpServletResponse)方法,这说明子类可以去覆盖service(HttpServletRequest,HttpServletResponse)方法即可,这就不用自己去

强转请求和响应对象了。


(2)其实子类也不用去覆盖service(HttpServletRequest,HttpServletResponse)方法,因为HttpServlet还要做另一步简化操作,下面会介绍。

20190810225456956.png

2>. doGet()和doPost()


①. 在HttpServlet的service(HttpServletRequest,HttpServletResponse)方法会去判断当前请求是GET还是POST,如果是GET请求,那么会去调用本类的doGet()方法,如果是POST请求会去调用doPost()方法,这说明我们在子类中去覆盖doGet()或doPost()方法即可


②. 如果只重写了doGet( )或doPost( ),当我们访问这个路径的时候,servlet中没有对应的doGet()或dopost的时候会抛出405


20190810225842271.png

5. servet细节


1>.Servlet与线程安全


* Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的

* 多个用户同时访问时,可能存在线程安全问题。

* 解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值


2>. 让服务器在启动时就创建Servlet


默认情况下,服务器会在某个Servlet第一次收到请求时创建它。也可以在web.xml中对Servlet进行配置,使服务器启动时就创建Servlet。


在servlet元素中配置load-on-startup元素可以让服务器在启动时就创建该Servlet,其中load-on-startup元素的值必须是大于等于的整数,它的使用是服务器启动时创建Servlet的顺序。上例中,根据load-on-startup的值可以得知服务器创建Servlet的顺序为Hello1Servlet、Hello2Servlet、Hello3Servlet。

20190812134909697.png

* 在<servlet>标签下配置
    1. 第一次被访问时,创建
                * <load-on-startup>的值为负数
            2. 在服务器启动时,创建
                    * <load-on-startup>的值为0或正整数



3>.url-pattern

1. urlpartten:Servlet访问路径
  1. 一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"})
注意:如果只配置一个那么{ }可以省略
  2. 路径定义规则:
  1. /xxx:路径匹配
  2. /xxx/xxx:多层路径,目录结构
  3. *.do:扩展名匹配(*不能配置多个 *不能配置在中间)
注意: 如果一个servlet配置了/*,他会将所有的jsp、html等静态资源都拦截掉
2. / 和 /* 的区别
  / 不会拦截  xx.jsp 
  /* 会拦截所有的包括xx.jsp在内


①. 可以在servlet-mapping中给出多个url-pattern,例如:

20190812140005883.png


那么这说明一个Servlet绑定了两个URL,无论访问/AServlet还是/BServlet,访问的都是AServlet


②. 还可以在 url-pattern 中使用通配符,所谓通配符就是星号“*”,星号可以匹配任何URL前缀或后缀,使用通配符可以命名一个Servlet绑定一组URL,例如:

20190812140205738.png


请注意,通配符要么为前缀,要么为后缀,不能出现在URL中间位置,也不能只有通配符。例如:/*.do就是错误的,因为星号出现在URL的中间位置上了。*.*也是不对的,因为一个URL中最多只能出现一个通配符。

20190820104125599.png



④. ServletContext


6. ServletContext

20190812192816820.png

1>.ServletContext概述


ServletContext对象的作用是在整个Web应用的动态资源之间共享数据!例如在AServlet中向ServletContext对象中保存一个值,然后在BServlet中就可以获取这个值,这就是共享数据了


①. 服务器会为每个应用创建一个ServletContext对象:


②. ServletContext对象的创建是在服务器启动时完成的;


③. ServletContext对象的销毁是在服务器关闭时完成的。


2>. 获取ServletContext

①.在Servlet中获取ServletContext对象:
public class MyServlet implements Servlet {
public void init(ServletConfig config) {
    ServletContext context = config.getServletContext();
}
}



②.在GenericeServlet或HttpServlet中获取ServletContext对象:

public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) {
    ServletContext context = this.getServletContext();
}
}



③. 通过request对象来调用方法获取

ServletContext context1=request.getServletContext( );


④. 通过监听器中获取

public void contextInitialized(ServletContextEvent servletContextEvent) {
        //加载资源文件
        //1.获取ServletContext对象
        ServletContext servletContext = servletContextEvent.getServletContext();


3>. 域对象的功能


所有域对象都有存取数据的功能,因为域对象内部有一个Map,用来存储数据,下面是ServletContext对象用来操作数据的方法:


①. void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性例如:servletContext.setAttribute(“xxx”, “XXX”),在ServletContext中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同


②. Object getAttribute(String name):用来获取ServletContext中的数据,当前在获取之前需要先去存储才行,例如:String value = (String)servletContext.getAttribute(“xxx”);,获取名为xxx的域属性;


③. void removeAttribute(String name):用来移除ServletContext中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;

20190812195103316.png



4>. 获取MIME类型


①. MIME类型:在互联网通信过程中定义的一种文本数据类型


②. 格式: 大类型/小类型 text/html image/jpeg


③. 获取:String getMimeType(String file)

//定义一个图片路径
        String filename="a.jpg";
        //2.获取ServletContext对象
        ServletContext app = this.getServletContext();
        //3.获取Mime类型
        String mimeType = app.getMimeType(filename);
        System.out.println(mimeType);//image/jpeg

 

5>. 获取文件的真实(服务器)路径


方法:String getRealPath(String path)

20190823145424767.png

20190820192802468.png

⑤. 请求Http


1.Http的概述


概念:Hyper Text Transfer Protocol 超文本传输协议(传输协议:定义了,客户端和服务器端通信时,发送数据的格式)

2. 特点

①. 基于TCP/IP的高级协议


②. 默认端口号:80[www.baidu.com:80]


③. 基于请求/响应模型的:一次请求对应一次响应


④. 无状态的:每次请求之间相互独立,不能交互数据


3. 请求消息数据格式


1>. 请求行

请求方式 请求url 请求协议/版本(GET /login.html HTTP/1.1)
//掌握
* 请求方式:
  * HTTP协议有7中请求方式,常用的有2种
  * GET:
    1. 请求参数在请求行中,在url后。
    2. 请求的url长度有限制的
    3. 不太安全
  * POST:
    1. 请求参数在请求体中
    2. 请求的url长度没有限制的
    3. 相对安全


2>. 请求头


请求头:客户端浏览器告诉服务器一些信息(格式:请求头名称: 请求头值)


常见的请求头:

(1).User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息(可以在服务器端获取该头的信息,解决浏览器的兼容性问题)

(2).Referer:http://localhost/login.html* 告诉服务器,我(当前请求)从哪里来?

* 作用:

1. 防盗链:

2. 统计工作:

20190813234341572.png


3>.请求空行


空行,就是用于分割POST请求的请求头,和请求体的。


4>. 请求体(正文):


封装POST请求消息的请求参数的


20190813234858950.png


⑥. request

1. request原理 和 response对象的原理


①. request和response对象是由服务器创建的。我们来使用它们


②. request对象是来获取请求消息,response对象是来设置响应消息

20190813235723893.png

2.Request 继承体系


20190815095207906.png


3. Request的方法


20190820163803993.png


1>. 获取请求行数据


GET /day14/demo1?name=zhangsan HTTP/1.1


①. String getMethod( ) : 获取请求方式 :GET


②. String getContextPath( ) :获取虚拟目录:/day14


③. String getServletPath( ) : 获取Servlet路径: /demo1


④. String getQueryString( ) : 获取get方式请求参数:name=zhangsan


⑤. String getRequestURI( ): 获取请求URI:/day14/demo1


⑥. StringBuffer getRequestURL( ) :http://localhost/day14/demo1


区别:

URL:统一资源定位符 : http://localhost/day14/demo1 中华人民共和国

URI:统一资源标识符 : /day14/demo1 共和国(范围大)

⑦. String getProtocol( ):获取协议及版本:HTTP/1.1


⑧. String getRemoteAddr( ):获取客户机的IP地址:

20190820163950674.png


protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*
            1. 获取请求方式 :GET
                * String getMethod()
            2. (*)获取虚拟目录:/day14
                * String getContextPath()
            3. 获取Servlet路径: /requestDemo1
                * String getServletPath()
            4. 获取get方式请求参数:name=zhangsan
                * String getQueryString()
            5. (*)获取请求URI:/day14/demo1
                * String getRequestURI():   /day14/requestDemo1
                * StringBuffer getRequestURL()  :http://localhost/day14/requestDemo1
            6. 获取协议及版本:HTTP/1.1
                * String getProtocol()
            7. 获取客户机的IP地址:
                * String getRemoteAddr()
         */
        //1. 获取请求方式 :GET
        String method = request.getMethod();
        System.out.println(method);
        //2.(*)获取虚拟目录:/day14
        String contextPath = request.getContextPath();
        System.out.println(contextPath);
        //3. 获取Servlet路径: /demo1
        String servletPath = request.getServletPath();
        System.out.println(servletPath);
        //4. 获取get方式请求参数:name=zhangsan
        String queryString = request.getQueryString();
        System.out.println(queryString);
        //5.(*)获取请求URI:/day14/demo1
        String requestURI = request.getRequestURI();
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURI);
        System.out.println(requestURL);
        //6. 获取协议及版本:HTTP/1.1
        String protocol = request.getProtocol();
        System.out.println(protocol);
        //7. 获取客户机的IP地址:
        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);
    }

 

2>. 获取请求头数据


①. String getHeader(String name):通过请求头的名称获取请求头的值


②. Enumeration<String> getHeaderNames( ):获取所有的请求头名称

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //演示获取请求头数据
        //1.获取所有请求头名称
        Enumeration<String> headerNames = request.getHeaderNames();
        //2.遍历
        while(headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            //根据名称获取请求头的值
            String value = request.getHeader(name);
            System.out.println(name+"---"+value);
        }
    }

 

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //演示获取请求头数据:user-agent
        String agent = request.getHeader("user-agent");
        //判断agent的浏览器版本
        if(agent.contains("Chrome")){
            //谷歌
            System.out.println("谷歌来了...");
        }else if(agent.contains("Firefox")){
            //火狐
            System.out.println("火狐来了...");
        }
    }
}

3>. 获取请求体数据


请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数


①. BufferedReader getReader():获取字符输入流,只能操作字符数据


②. ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据 ( 在文件上传知识点后讲解 )

20190815111842862.png



4>. 其他功能 ( 掌握 )


1. 获取请求参数通用方式:不论get还是post请求方式都可以使用下列方法来获取请求参数


①. String getParameter(String name):根据参数名称获取参数值 username=zs&password=123


②. String[ ] getParameterValues(String name):根据参数名称获取参数值的数组 hobby=xx&hobby=game


③. Enumeration getParameterNames( ):获取所有请求的参数名称


④. Map<String,String[ ]> getParameterMap( ):获取所有参数的map集合

* 中文乱码问题:
  * get方式:tomcat 8 已经将get方式乱码问题解决了
  * post方式:会乱码
  * 解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post 获取请求参数
        //根据参数名称获取参数值
        String username = request.getParameter("username");
       /* System.out.println("post");
        System.out.println(username);*/
       //根据参数名称获取参数值的数组
        String[] hobbies = request.getParameterValues("hobby");
        /*for (String hobby : hobbies) {
            System.out.println(hobby);
        }*/
        //获取所有请求的参数名称
        Enumeration<String> parameterNames = request.getParameterNames();
        /*while(parameterNames.hasMoreElements()){
            String name = parameterNames.nextElement();
            System.out.println(name);
            //如果是复选框选中多个,只能获取一个值
            String value = request.getParameter(name);
            System.out.println(value); 
            System.out.println("----------------");
        }*/
        // 获取所有参数的map集合
        Map<String, String[]> parameterMap = request.getParameterMap();
        //遍历
        Set<String> keyset = parameterMap.keySet();
        for (String name : keyset) {
            //获取键获取值
            String[] values = parameterMap.get(name);
            System.out.println(name);
            for (String value : values) {
                System.out.println(value);
            }
            System.out.println("-----------------");
        }

 


2. 请求转发:一种在服务器内部的资源跳转方式


①. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)


②. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)

20190815161415840.png


特点:

1. 浏览器地址栏路径不发生变化

2. 转发只能访问当前服务器下的资源

3. 转发是一次请求,可以使用request共享数据


3. 域对象(共享数据)


域对象:一个有作用范围的对象,可以在范围内共享数据

request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据


①. void setAttribute(String name,Object obj):存储数据


②. Object getAttitude(String name):通过键获取值


③. void removeAttribute(String name):通过键移除键值对


4.获取ServletContext


ServletContext getServletContext( )

20190821095938793.png


4. 登录案列

20190821144811358.png



1>.需求:


* 用户登录案例需求:

1.编写login.html登录页面

 username & password 两个输入框

2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表

3.使用JdbcTemplate技术封装JDBC

4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您

5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误

20190815170514478.png

2>.开发步骤

1. 创建项目,导入html页面,配置文件,jar包
2. 创建数据库环境
  CREATE DATABASE day14;
  USE day14;
  CREATE TABLE USER(
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(32) UNIQUE NOT NULL,
  PASSWORD VARCHAR(32) NOT NULL
  );
3. 创建包cn.itcast.domain,创建类User
  package cn.itcast.domain;
  /**
  * 用户的实体类
  */
  public class User {
     private int id;
     private String username;
     private String password;
     public int getId() {
         return id;
     }
     public void setId(int id) {
         this.id = id;
     }
     public String getUsername() {
         return username;
     }
     public void setUsername(String username) {
         this.username = username;
     }
     public String getPassword() {
         return password;
     }
     public void setPassword(String password) {
         this.password = password;
     }
     @Override
     public String toString() {
         return "User{" +
                 "id=" + id +
                 ", username='" + username + '\'' +
                 ", password='" + password + '\'' +
                 '}';
     }
  }


3>. 创建包cn.itcast.util,编写工具类JDBCUtils

/**
  * JDBC工具类 使用Durid连接池
  */
  public class JDBCUtils {
     private static DataSource ds ;
     static {
         try {
             //1.加载配置文件
             Properties pro = new Properties();
             //使用ClassLoader加载配置文件,获取字节输入流
             InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
             pro.load(is);
             //2.初始化连接池对象
             ds = DruidDataSourceFactory.createDataSource(pro);
         } catch (IOException e) {
             e.printStackTrace();
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
     /**
      * 获取连接池对象
      */
     public static DataSource getDataSource(){
         return ds;
     }
     /**
      * 获取连接Connection对象
      */
     public static Connection getConnection() throws SQLException {
         return  ds.getConnection();
     }
  }


4>. 创建包cn.itcast.dao,创建类UserDao,提供login方法

/**
  * 操作数据库中User表的类
  */
  public class UserDao {
     //声明JDBCTemplate对象共用
     private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
     /**
      * 登录方法
      * @param loginUser 只有用户名和密码
      * @return user包含用户全部数据,没有查询到,返回null
      */
     public User login(User loginUser){
         try {
             //1.编写sql
             String sql = "select * from user where username = ? and password = ?";
             //2.调用query方法
             User user = template.queryForObject(sql,
                     new BeanPropertyRowMapper<User>(User.class),
                     loginUser.getUsername(), loginUser.getPassword());
             return user;
         } catch (DataAccessException e) {
             e.printStackTrace();//记录日志
             return null;
         }
     }
  }


5>. 编写cn.itcast.web.servlet.LoginServlet类

@WebServlet("/loginServlet")
  public class LoginServlet extends HttpServlet { 
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         //1.设置编码
         req.setCharacterEncoding("utf-8");
         //2.获取请求参数
         String username = req.getParameter("username");
         String password = req.getParameter("password");
         //3.封装user对象
         User loginUser = new User();
         loginUser.setUsername(username);
         loginUser.setPassword(password);
         //4.调用UserDao的login方法
         UserDao dao = new UserDao();
         User user = dao.login(loginUser);
         //5.判断user
         if(user == null){
             //登录失败
             req.getRequestDispatcher("/failServlet").forward(req,resp);
         }else{
             //登录成功
             //存储数据
             req.setAttribute("user",user);
             //转发
             req.getRequestDispatcher("/successServlet").forward(req,resp);
         }
     }
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         this.doGet(req,resp);
     }
  }


6>.登录成功或失败

@WebServlet("/successServlet")
  public class SuccessServlet extends HttpServlet {
      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          //获取request域中共享的user对象
          User user = (User) request.getAttribute("user");
          if(user != null){
              //给页面写一句话
              //设置编码
              response.setContentType("text/html;charset=utf-8");
              //输出
              response.getWriter().write("登录成功!"+user.getUsername()+",欢迎您");
          } 
      }  
  @WebServlet("/failServlet")
  public class FailServlet extends HttpServlet {
      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          //给页面写一句话
          //设置编码
          response.setContentType("text/html;charset=utf-8");
          //输出
          response.getWriter().write("登录失败,用户名或密码错误");
      }
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          this.doPost(request,response);
      }
  }



5. BeanUtils工具类,简化数据封装


作用:用于封装JavaBean的

1>. JavaBean:标准的Java类


1. 要求:

1. 类必须被public修饰

2. 必须提供空参的构造器

3. 成员变量必须使用private修饰

4. 提供公共setter和getter方法

2. 功能:封装数据


2>. 概念:


成员变量:


属性:setter和getter方法截取后的产物


例如:getUsername() --> Username–> username


3>. 方法:


①. void setProperty(Object bean, String name, Object value ):操作的是属性,不是成员变量


②. String getProperty(Object bean, String name )


③. void populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中


20190817223704236.png

20190817223802499.png


关于热部署问题:一定要记得debug模式才生效

20190820170136161.png

⑦.响应HTTP

1. HTTP响应消息

* 响应字符串格式
    //请求行
  HTTP/1.1 200 OK
  //请求头
  Content-Type: text/html;charset=UTF-8
  Content-Length: 101
  Date: Wed, 06 Jun 2018 07:08:42 GMT
   //请求空行
   //请求体
  <html>
   <head>
     <title>$Title$</title>
   </head>
   <body>
   hello , response
   </body>
  </html>


2.响应行


HTTP/1.1 200 OK

1.组成 :协议/版本 响应状态码 状态码描述

2.响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态


1. 状态码都是3位数字

2. 分类:

1. 1xx:服务器接收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码

2. 2xx:成功。代表:200

3. 3xx:重定向。代表:302(重定向),304(访问缓存)

4. 4xx:客户端错误。

 * 代表:

  * 404(请求路径没有对应的资源)

  * 405:请求方式没有对应的doXxx方法

5. 5xx:服务器端错误。代表:500(服务器内部出现异常)


3.响应头


响应头

Content-Type: text/html;charset=UTF-8

Content-Length: 101

Date: Wed, 06 Jun 2018 07:08:42 GMT


1. 格式:头名称: 值

2. 常见的响应头:

1. Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式

2. Content-disposition:服务器告诉客户端以什么格式打开响应体数据

 * 值:

  * in-line:默认值,在当前页面内打开

  * attachment;filename=xxx:以附件形式打开响应体。文件下载


4.响应空行


5.响应体


传输的数据

20190818082611871.png



相关文章
|
6月前
|
JSON Java 应用服务中间件
|
6月前
|
Java 应用服务中间件 数据库连接
Servlet是什么?
Servlet(Server Applet)是Java Servlet的简称,通常被称为小服务程序或服务连接器。它是一个用Java编写的服务器端程序,具有独立于平台和协议的特性。Servlet的主要功能在于交互式地浏览和生成数据,进而生成动态Web内容。
52 3
|
6月前
|
XML 前端开发 Java
servlet使用
servlet使用
|
应用服务中间件
Servlet2(2)
Servlet2(2)
67 0
|
Java 应用服务中间件
Servlet2(1)
Servlet2(1)
67 0
|
JSON 前端开发 Java
Servlet详解(下)
Servlet详解
75 0
|
XML JavaScript 前端开发
servlet详解
servlet详解
|
小程序 Java 应用服务中间件
Servlet1(1)
Servlet1(1)
78 0
|
应用服务中间件
Servlet的详细使用(上)
Servlet的详细使用(上)
95 0
Servlet的详细使用(下)
Servlet的详细使用(下)
55 0