Servlet|学习笔记

简介: 快速学习Servlet

开发者学堂课程【高校精品课-上海交通大学 -互联网应用开发技术:Servlet】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/76/detail/15753


Servlet


书籍编辑是演示的在前端可以编辑因为没有后端所以没法写到数据库里,可能页面一刷新就回去是允许的,但是要有编辑功能,未来配后端之后强大的编辑就可以写到后端去。比如要求有一个管理员可以增加图书的种类,图书种类不可能肯定给管理员在前端打开页面以后去增加新的书或者修改库存,修改单价的一些功能。

 

WEB 后端-SERVLET

Servlet 尽管最系统框架可能是用 spring controller,如果用 SSH 框架不用 spring mvc,比如用 struts的 mvc 可能用的是 action。无论用哪一种最终的实现逻辑是一样的,两个是在 Servlet 上面封装出来,工作原理是一样的。尽管可能不会使用 Servlet 最终在代码里面写,会用框架但基本道理类似。

1、Servlet

What is Servlet

ServletAPI

Examples

Web applications are of the following types:

Presentation-oriented: A presentation-oriented web applicati on generates interactive web pages containing various types of markup language(HTMLXHTMLXMLand so on)and dynamic contentin response to requests.

Service-oriented:A service-oriented web application implem ents the endpoint of a web service. Presentation-oriented app lications are often clients ofservice-oriented web applications.

image.png

Web 应用分两种,一种是给人用呈现 Web 页面,一种是给面向服务给其他的程序去用,会产生请求发过来,发过来之后就有服务器把请求封装,比如在发请求里面带参数,像页面里看到的让用户填东西,最后 submit 一下,东西会打包以后作为参数传递到服务器端,服务器端像 tomcat 会把接触到的请求封装到对象里,传递给写的 Web 空间,比如 Servlet 里面,然后 Servlet 解析里面的内容去做相应处理,处理是去掉其他后台的东西或者跟数据库交互,完全是后台做的事情,然后在 tomcat 把请求传递过来的同时,还给了一个空的响应,Servlet 要把处理完的结果写到响应里,响应就返回给客户端,相应相当于 HTML 的脚本,页面发回到客户端之后,客户端浏览器呈现出来就完成了一次交互。可以看到有很多事情是 tomcat 帮忙做,比如接收到一个请求之后,是纯文本过来的情求怎样变成 Java 的 httpservlet request对象,以及怎样生成一个空的 http servlet response 对象,把两个对象传递给 serclet 都不是自己做的,tomcat 帮忙做,从意义上来说有很多东西不是自己写 tomcat 帮忙做,所以不可能单独跑,只能部署在里面去用 tomcat 功能。Servlet 要做的是在前端封装好两个的对象,一个是请求一个是响应,响应一开始都是空的,要对着响应写进去将来要发挥客观的东西,请求是把客户端发过来的请求,不管是通过 ES script 发的还是通过超链接发的,只要请求过来,就封装在 httpservice request 里。

A web application consists of

web components;

static resource filessuch as images and cascading style sheets(CSS)

and helper classes and libraries.

The web container provides many supporting services that enhance the capabilities of web components and make them easier to develop.

Web 控件要么是 servlet,要么 spring controller,要么是 struts Action ,属于这一类。一个 Web 应用包含首先是 Web 控件,然后有静态的一些页面,还有前端的一些脚本,有前端的有后端的。把前后端隔离,后端至少 Web 控件,然后有编辑出来很多类依赖的包,还有需要的一些在后台传递给前台的其他资源,比如静态的一些页面等等。Web 容器提供很多的支持服务,接收请求、封装对象之后帮忙去管理连接池,帮忙管理 servlet 对象创建几个的问题,只要关注业务逻辑去写类就可以,至于类到底创建多少个对象全部由 container 托管,container 对于每一个部署在里面应用的 Web 控件都会生成一个 web 的容器托管起来。相当于人穿外骨骼上战场,只关心大脑人去控制,外骨骼可以非常强帮忙做很多事情,整个人穿在外骨骼里面才能上战场,单个人没有任何武装不能上战场,外骨骼本身是 container 帮忙制造的,所以在代码里看到了大量的education 或者用 XML 的方式去描述,讲希望怎样帮忙去量身定造,在自己的代码里面告诉它希望怎样定制。

However,

because a web application must take these services into account the process for creating and running a web application is different from that of traditional stand-alone Java classes

The process for creating,deploying,and executing a web application can be summarized as follows:

(1)Develop the web component code.

(2)Develop the web application deployment descriptor if necessary

(3)Compile the web application components and helper classes referenced by the components.

(4)Optionally package the application into a deployable unit.

(5)Deploy the application into a web container

(6)Access a URL that references the web application

开发一个 Web 应用需要开始开发,然后写部署描述符 XML 或者application 的东西,再告诉拿到代码之后告诉 container 怎样量身定造一个容器然后把东西编译完打包以后变成比如看到 WAR 包WAR 包会扔到应用服务器指定的目录下,用 container 应用服务器生成一个容器,把写的东西扔到容器里是一个完整的过程

What is servlet?

Aservlet is a Java programming language class used to extend

the capabilities of servers that host applications accessed by means of a request-response programming model.

Although servlets can respond to any type of request they are

commonly used to extend the applications hosted by web servers.

For such applications, Java Servlet technology defines HTTP -specific servlet classes.

The javax. servlet and javax.servlet.http packages provide interfaces and classes for writing servlets.

All servlets must implement the Servlet interfacewhich defines

lifecycle methods.

When implementing a generic serviceyou can use or extend

the GenericServlet class provided with the Java Servlet API.

The HttpServletclass provides methodssuch as doGet and doPost,for handling HTTP-specific services.

Spring 的 controller 和 struts 的 action 都是基于 servlet 封装的,servlet 是一种请求响应 HTTP 编程模型的一个具体实现,只是在后台响应 HTTP 的请求产生响应的报文,发挥到前端,前端就可以看到。Servlet 问题是整个 tomcat 加上 APP 整个运行在一个JVM 里面 Java 虚拟机里,Java 虚拟机写的代码不能直接跑一块,把 Java 的字节码解析以后在机上跑,整个 Java 虚拟机是一个进程,所以 servlet 是一整个应用和 tomcat 合起来在一个进程里跑,所以 servlet 实际上至多只是一个线程,servlet 可以有多个实例,多个实例可以是多个线程,线程意味着线程和线程之间可以共享同一个进程里的所有资源,设有一个潜在的安全问题,线程编程里边只是有概念,servlet 是不是线程安全,因为没有学操作系统所以不去展开解释,可以是安全的也可以是不安全,就在于有没有实现一个特定的接口。

Tomcat+APP=>JVM->1 process  1thread

写 servlet 是在一个指定的 url 上去等待用户的请求,然后会产生响应,写的所有 servlet 一般都是集成子 http service class 类。然后里面有像 doget、dopost 的方法,对应的 HTTP 请求发过来是用 get 方法发的,tomcat 在接收到请求帮组一个空的 http service request 会去掉写的 servlet doget 的方法。如果是 post方法过来会调 dopost 方法,以此类推还有 doput、dodelete 常用的四个方法。


2、Servlet Container

(1)Container types

image.png

代码在容器里跑,浏览器发过来的请求被封装封装以后传递给一个请求,封装过来之后上面有参数,还有 getpost 方法这些东西全部都传递过来,传递过来之后会去决定调 servlet doget 还是dopost 的方法,方法呢都有参数,参数包括组装出来的请求对象和响应对象代码关注于怎么去处理请求和响应就可以,怎么包装出的对象,怎么传递过来,怎么会调用 get 全都不管。所以在容器的世界里代码永远不可能单独执行功能不全,只关心于业务逻辑,其他问题全部是容器提供


(2)An Example

The following is a typical sequence ofevents:

Aclient(eg,a Web browseraccesses a Web server and makes an HTTP request.

The request is received by the Web server and handed off to the servlet container

The servlet container can be running in the same process as the host Web server, in a different process on the same hostor on a different host from the Web server for which it processes requests.

The servlet container determines which servlet to invoke based on the configuration ofits servletsand calls it with objects representing the requestand response.

The servlet uses the request object to find out who the remote user is,what HTTP POST parameters may have been sent as part of this request and other relevant data.

The servlet performs whatever logic it was programmed withand generates data to send back to the client.It sends this data back to the client via the response object.

Once the servlet has finished processing the requestthe servlet container ensures that the response is properly flushedand returns control back to the host Web server.

完整的过程浏览器会发出一个 HTTP 的请求,请求会发送到 Web服务器端,请求 container Web 服务器接收到之后会交给某一个 servlet 容器一个 servlet 有一个容器,交给哪一个是看 servlet 监听什么样的应用,比如 _report  url  local host 8080然后工程 _report 的这种请求就发给这个 servlet ,如果是后面有其他路径发给其他的 servlet ,根据路径的声明发给容器,容器要把配置决定要传递给谁,传递是 servlet 在容器里面可以有一个实例,也可以有 N 个实例,哪一种要看当时的配置,如果是 N 个要给谁要靠容器来做。都不用关心,只写一个 servlet 类,至于创建几个对象不用关心,请求到底给哪个对象去处理也不用关心,只知道业务逻辑怎么做就可以。servlet 在有请求,服务器最端在接收到请求之后会组装出一个请求对象和响应对象,会把请求和响应根据当时发的请求里面的方法是 get 还是 post 来调, servlet doget 还是 dopost 的方法,两个方法才是自己写的代码,想干什么就干什么,然后去写 response,把 response 里面内容写进去之后,就会被返回给客户端的浏览器,是浏览器看到的结果。


3、Creating a Servlet

Use the @WebServlet annotation to define a servlet component in a web application.

The annotated servlet must specify at least one URL pattern

This is done by using the urlPatterns or value attribute on the

annotation.

import javax.servlet.annotation.Webservlet;

import javax.servlet.http.Httpservlet;

@WebServlet("/report")

public class MoodServlet extends HttpServlet {

...

The web container initializes a servlet after loading and instantiating the servlet class and before delivering requests from clients.

随便写一个 servlet 类,基本上都扩展至 httpservlet class ,annotation 本身是给比如要去部署 tomcat 里是给框架或者用户去看,这个是给 tomcat 看,前面是名字,web service 就是加企业版规定,tomcat 遵循协议。通过 annotation 来描述 servlet 是在真听哪一种 url,所以如果前面是工程名单 http://127.0.0.1:8080/progect/report ,因为在工程里所以前一半只写相对路径名,前一半不写,凡是后面跟着是 report 无论怎么发请求,都是被 MoodServlet 处理。

(1)The Servlet Interface

The Servlet interface is the central abstraction ofthe lava Servlet API.

All servlets implement this interface either directly or more commonly by extending a class that implements the interface.

The two classes in the Java Servlet API that implement the Servlet interface are GenericServlet andHttpServlet.

For most purposesDevelopers will extend HttpServlet to implement their servlets.

servlet 处理首先要实现扩展 HttpServlet ,不一定非要扩展,还有General service 类也可以扩展但不常用。写的东西都是扩展自 HttpServlet 。


2)HTTP Specific Request Handing Methods

HttpServlet class has methods to aid in processing HTTP based requests:

doGet for handling HTTP GET requests

doPost for handling HTTP POST requests

doPut for handling HTTP PUT requests

doDelete for handling HTTP DELETE requests

doHead for handling HTTP HEAD requests

doOptions for handling HTTP OPTIONS requests

doTrace for handling HTTP TRACE requests

Typically when developing HTTP-based servletsa Servlet Developer will only concern himself with the doGet and doPost methods.

会有 doget 、dopost 、dodelete ,对应的是如果发送过来的请求是 get、post、put、delete 是什么就调哪个方法,是应用服务器 tpmcat 来直接调。


(3)An Example:mood

@WebServlet("/report")

public class MoodServlet extends HttpServlet{

protected void processRequest(HttpServletRequest request,Htt pServletResponse response)

throws ServletException,IOException {

response.setContentType("text/html;charset=UTF-8"); PrintWriter out =response.getWriter(); try {

out.println("<html lang=\"en\">"); out.println("<head>");

out.println("<title>Servlet MoodServlet</title>");

out.println("</head>"); out.println("<body>");

out.println("<h1>Servlet Moodservlet at “+

request.getContextPath() + "</h1>");

request.setAttribute("mood", "sleep");

String mood = (String) request.getAttribute("mood");

out.println("<p>Duke's mood is: " + mood + "</p >");

if (mood.equals("sleepy")) {

out.println("< img src= "resources/images/duke.snooze.gif\" alt= "Duke sleeping\"/><br/>");

} else{

...

}

out.println("</body>");

out.println("</html>");

}finally {

out.close();

}

}

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html;charset=UTF-8"); processRequest(request,response);

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

processRequest(request, response);

)

}

完整代码首先 servlet 监听 Webservlet 位置,然后 doget 参数是 HttpServletRequest 类型的对象,requset 是 tomcat 封装的,把客户端 Http 请求封装成 java 对象传进来,respone 是空对象,希望在往里面填进响应。只要 get 到,就接收封装好的 request 和一个空的 response。下面的逻辑自己选择,比如会设置 response里面的参数,它的类型要返给一个 http 页面,字符集使用 UTF-8因为要支持中文。下面的具体逻辑写一个函数,把 request、response 传递过去。如果是 dopost 参数列表是一样的,request 是传递过来的请求以及空的 respone。验证比较简单不区分 get、post 随便哪一种都可以,都要自己写方法来实现,方法是前面的逻辑。后面两个什么都没做直接原封不动,可以请求参数传递给process、 request,在 process、request 里面仍然能得到 request、respone,具体执行的时候在 response 上获取一个 Writer对象,往里面写内容,写 html 的脚本,前面是 html 的一行,然后是 head ,head 里面只有一个 title,然后是 body ,body里面是h1。H1 的方式显示一行内容request get contextpath,request 是tomcat 包装出来的对象,还有一个上下文,获取上下文路径实际上是在告诉在哪里发生,调谁。很少用到,只是在告诉你能打印出来这种东西 request 相关的。输出变量值,然后再打了省略号,最后是body、html 的结束,全部写完之后在过程中,有可能有问题,跟C++ 里面的抛异常一样会 try cash,但是没有 cash 所以遇到异常也没办法,直接抛出来,在方法里会抛出异常,不管抛异常还是不抛异常都要执行 finally,要把 response 上的 writer 对象 close 掉,一旦 close 响应会被刷回到客户端,所以客户端要么看到抛的异常站,要么是看到完整的页面。

“request.setAttribute("mood", "sleep");String mood = (String) request.getAttribute("mood "); ”request 对象在 tomcat 帮忙封装,会把客户端传递进来的一些参数都放里面,所以在调用 get parameter 的时候可以得到里面的一些参数。Request 还存在一种用法是一个请求过来之后,通过一个类处理过之后,不会马上返回客户端,希望把这个请求继续传递给下一个类进行处理,但是希望在得到请求之后,在请求上加一点东西,然后把请求转发给下一个类。下一个类是 servlet 类,拦截掉之后能够做一些处理,加一些信息上去,把请求再给 servlet 处理,filter 用类来表示,类处理结果传递给下一个请求,就下一个类去做处理需要在请求上面设置一个属性,属性名字随便起,后面是它的值,这行代码的意思是在 servlet 里面在上面设了一个属性,属性的值是是 sleep。然后在属性上直接去get Attribute,刚设完 sleep 所以 get 出来肯定还是 sleep。看两行代码时候会感觉有点犹豫,自己设一个 mood 属性 sleep ,马上把 mood 取出来,不直接 sleep 意思是告诉有一个机制,可以在 request 上去设属性,首先记住机制,上面是要在 filter 里完成为后面做铺垫。整个代码可以执行,执行完的效果会去某个目录里,拿出一张图片去展示的。


4、Servlet Sample

(1)New Maven Project-Create from archtetype

开发用的时候建议使 Maven,spring lnitlallzr 也可以选择需要的功能,一般用空的 Maven 做。是一个 webapp 所以需要选择上 Create from archetype 点一下下面才能选,选择 webapp 开发一个 web 的应用。

image.png


(2)Create source and resource folders

image.png

开发完之后要注意的是 Maven 在默认的情况下配的不是自己想要的,比如会显示五或者六,要把它选成机器当前装的 JDK 版本。如果是 Windows 在 filiter 下面有 project structur,点开界面。如果是 mark 下面位置稍微有差异,在目录里面点出来,点开之后在 models 地方选语言的级别应该是机上装的 JDK,然后可以去设置一个目录,选中一个目录点一个 source,知道源代码的位置,再给出一个目录去选 resource,就知道 resource,resource 是图片,图片会压缩到里面去。


(3)Edit Conf

image.png

运行要配 tomcat 服务器,跑起来之后下面的路径是默认的,因为工程的名字为 se122 7_servletsamples ,部署的时候压成了一个 war包,也可以不压直接目录放到 tomcat webapp 里,目录不用管会自动出来。

image.png

在运行的时候然如果在不同的情况下去调用,传递过去的参数不一样。一个是 hungry,一个是 pensive,一个是 toughtful ,会取不同的图片出来。


(4)工程的完整样子

image.png

image.png

import

@WebServlet("/report")

public class MoodServlet extends HttpServlet {

private static final long serialVersionUID =189253777748894 13L;

/**

* Processes requests for both HTTP <code>GET</code> and <code>POST</code>

* methods.

* @param request servlet request

* @param response servlet response

* @throws ServletException if a servlet-specific error occurs

* @throws I0Exception if an 1/0 error occurs

*/

protected void processRequest(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html;charset=UTF-8); PrintWriter out=response.getwriter();

try {

out.println("<html lang=1"en\" “);

out.println("<head>");

out.println("<title>Servlet MoodServlet</titles")

out.println(“</head>“);

out.println("<body>");

out.println("<h1>Servlet MoodServlet at "

+ request.getContextPath() + "</h1>");

// request.setAttribute("mood", "sleepy");

String mood =(String) request.getAttribute( s:"mood");

// String mood =(String)request.getParameter("mood");

//out.println("<p>Duke's mood is: " + mood + "</p >");

If(mood.equals("sleepy")) {

out.println("< img src=\"resources/images/duke.snooze.gif\" alt=\"Duke sle

} else if (mood.equals("alert")) {

out.println("< img src=\"resources/images/duke.waving.gif\" alt=\"Duke wav

} else if (mood.equals("hungry")) {

out.println("< img src=\"resources/images/duke.cookies.qif\" alt=!"Duke wi

} else if (mood.equals("lethargic")) {

out.println("< img src=\"resources/images/duke.handsOnHips.gif\" alt=\"Dul

} else if (mood.equals("thoughtful")) {

out.println("< img src=\"resources/images/duke.pensive.gif\" alt=\"Duke th

} else {

out.println("< img src=\"resources/images/duke.thumbsup.gi f\" alt=\"Duke w

}

out.println("</body>");

out.println("</html>");

} finally {

out.close();

}

}

HttpServlet methods. Click on the + sign on the left to edit the code.

}

MoodServlet 监听 report,逻辑在处理的时候在 respone 上获取 writer,然后在里面会写入脚本。可以看到“// request.setAttribute("mood", "sleepy"); String mood =(String) request.getAttribute( s:"mood");// String mood =(String)request.getParameter("mood"); ”注释掉,最初代码不是这个样子。可以看到在真正应用中不是在 set' 里设置的,是在 request 当前 servlet 里面,直接取属性出来。

mood ="alert";

break;

case 11;

case 15;

mood = "in need of coffee";

break;

case 19;

case 20;

case 21;

mood = "thoughtful";

break;

case 22;

mood = "lethargic";

break;

}

req.setAttribute( s: "mood", mood);

chain.doFilter(req,res);

}

属性是在前面被设置的,所以在一个类里面被设置另外一个类里面拿到。

得到 mood 属性,然后根据属性的值决定,不同的值就连接不同的图片。

image.png 

代码里问号后面出现的意思是这是 HTTP 请求的一个参数所以在里可以看到注释语句里面是从 request 里面获取参数 wood 类型的参数然后到下面去输出。所以也可以在命令行里面直接打参数,是 mood-hungry 信息被 tomcat 封装到 request 里面。所以在代码里面才能直接是 getParameter 把 mood 答出来。


(5)The generated html page

<html lang="en">

<head>

<title>Servlet MoodServlet</title>

</head>

<body>

<h1>Servlet MoodServlet at/ServletMood</h1>

<p>Duke's mood is: sleepy</p >

< img src="resources/images/duke.snooze.gif" alt="Duke sleeping"/><br/>

</body>

</html>

前端有一个页面。

把程序跑一下:

输入 report 结果:

Servlet MoodServlet at /se122_7_servletsamples_war

image.png

源码:

image.png

有 h1,有图片,图片里面有源,图片出不来显示的字,head 里面还有东西。工程里面没有任何一个刚才的页面,gsp 显示 hello world。

<html>

<body>

<h2>Hello World!</h2>

</body>

</html>

没有任何页面显示上一个页面看到的内容,内容是 servlet 写进来的一系列东西构成。整个页面是根据 servlet 生成的,servlet 判断 wood 是什么,sleep、ServletMood、resources/images/duke.sn ooze.gif 显示的内容和图片都可以根据实际情况的不同显示不同的内容,所以是一个动态页面。不同的用户传不同的参数进来看到的页面不同,后面传的参数不一样会显示不同的页面出来。


5、Filtering Requests and Responses

(1)Afilter is an object that can transform the header and content (or both )of a request or response.

①Filters differ from web components in that filters usually do not themselves create a response.

②Instead,a filter provides functionality that can be"attac hed"to any kind of web resource.

③Consequently,a filter should not have any dependencies on a web resource for which it is acting as a filter; this wayitcan be composed with more than one type of web resource.


(2)The main tasks that a filter can perform are as follows:

①Query the request and actaccordingly

②Block the request-and-response pair from passing any further

③Modify the request headers and data.You do this byproviding a customized version of the request.

④Modify the response headers and data.You do this by providing a ustomized version of the response.

⑤Interact with external resources.

在处理 servlet 之后不是直接对 response 产生作用,而是在request 里面添加一些新的信息,把请求继续转发下去给下一个类去处理。真正处理的是 servlet 在前端 filter过滤器来过滤请求做一些处理。

设计一个 filter 把请求或者响应里面的头或者内容做一些处理,然后本身跟 servlet 的控件是不同的,本身不产生任何响应只是在里面做一些处理,添加进去或者删除掉一些东西。然后会继续把这个请求传递下去,直到真正监听这个请求的 servlet 位置为止。到为止的原因是 filter 还可以串在一起形成一个链,第一个处理完,第二个处理,第二个处理完,第三个处理,最后才到 mood servlet。怎么做这件事,主要的作用是再干什么,比如看请求是什么根据请求做一些动作,然后会把请求和响应的对,tomcat 帮忙生成的封装请求以及空的响应一直往下传,传给下一个 filter 或者直接传到 servlet。主要的目的是修改头或者里面的内容,头或者内容包括请求、响应。


(3)Programming Filters

You define a filter by implementing the Filterinterface.

import javax.servlet.Filter;

import javax.servlet.annotation.Webfilter;

import javax.servlet.annotation.WebInitParam;

@WebFilter(filterName = "TimeOfDayFilter",

urlPatterns = {"/*"},

initParams = {

@WebInitParam(name = "mood", value = "awake")}

)

public class TimeOfDayFilter implements Filter { ....

具体例子写了 TimeOfDayFilter 的类,类实现的 filter 接口。然后监听的 url 是所有的,通配符所有的 url 过来,所有的请求必须先到 TimeOfDayFilter,处理完会继续往下走。有个初始化参数,初始化参数是 mood、awake。初始化 filter 的时候会给它 mood 变量初始化awake 

public class TimeOfDayFilter implements Filter {

String mood=null;@

Override

public void init(FilterConfig filterConfig) throws ServletExcepti on {

mood =filterConfig.getInitParameter("mood");

}

@Override

public void doFilter(ServletRequest reg, ServletResponse res, FilterChain chain)

throws IOException, ServletException {

Calendar cal=GregorianCalendar.getInstance();

switch (cal.get(Calendar.HOUR_OF_DAY)) {

case 23:case 24:case 1:case 2:case 3:case 4:case 5:case 6:

mood = "sleepy";

break;

...

}

req.setAttribute("mood",mood);

chain.doFilter(req,res);

}

@Override

public void destroy() {

}

}

所以尽管 mood 开始定义是 null ,在初始化 filter 实例的时候,会把 filter mood 设一个值是 awake。然后有 init 方法,容器在创建 filter 实例的时候,创建出来以后调用的方法,到刚才子 initparam 里面去找 mood 。getInitParameter mood 变量的值取出来 mood。所以只要实例初始化 mood 值就有,有之后初始化的值就是 awake。再拦截所有请求,所以所有请求来了都先到我这里,tomcat 会调 dofilter 方法。Dofilter 里面第一是 request,第二还是 response,道理一样肯定会包装好一个 request 给一个空的 response,目的是往里面写东西。Filter 可能不止一个,可能有多个,多个形成了一个链,要把链传递。获取当前的日期,日历对象,去取一下现在是几点,返回值是1到24,于是会有一个 switch 语句要是等于这些就再睡觉,等于其他的不管,对 mood 做了一下操作,mood 的值有可能不是初始的 awake。这一段操作不管怎么样 mood 值被改写掉之后,就在 request 上面去设置属性的值 mood,属性名是 mood,值是定义的 mood。所以在前面的代码里面,request.setAttribute("mood", "sleepy"); 实际上是没有的,实际上就注销掉了,为什么在 servlet 里面可以直接 get 出来,因为一个请求来之后,在监听所有请求所以先被 filter 处理。Filter 会在来的请求里面增加属性的 mood。最后在请求链上去调度 filter,然后处理完请求和响应继续往下传,也是 tomcat 定义好的东西也不用管,最后一句是 chain.doFilter(rec,res); 如果是链条里面中间一划 tomcat 会自动的把请求会响应转发给下一个 filter,如果是最后一个 filter 会转发给 servlet 的 doget。所有请求来了全部被 filter 拦截,在 request 里面增加一个属性 mood。所以在前面的代码里面,才能直接在 request 获取到 mood,这就是过滤的作用。

image.png

直接打 report 所有选择全部被拦截,然后 filter 会在 mood 里面增加一个属性 mood。然后跟后台 servlet mood 显示,所以看代码,所有的请求全部被 TimeOfDayFilter 拦截,拦截掉之后在 dofilter 里面,会说在睡觉,三个点到饭点,几个点是在上课,所以 alert 警醒状态,几个点是上课上到一半的时候需要休息一下,还有 toughtful 等等。不管如何最后 mood 有一个值,塞到 request里面继续往下传。

import ...

@WebFilter(filterName =“TimeOfDayFilter"

urlPatterns = {"/*"},

initParams = {

WebInitParam(name = "mood", value = "awake")})

public class TimeOfDayFilter implements Filter {

String mood = null;

@Override

public void init(FilterConfig filterConfig) throws ServletExcep tion {

mood = filterConfig.getInitParameter( s:"mood");

}

@Override

public void dofilter(ServletRequest req,

ServletResponse res,

FilterChain chain) throws I0Exception, ServletException {

Calendar cal=GregorianCalendar.getInstance();

switch (cal.get(Calendar.HOUR OF DAY)) {

case 23:

case 24:

case 1:

case 2:

case 3:

case 4:

case 5:

case 6:

mood = "sleepy";

break;

case 7:

case 13:

case 18:

mood = "hungry";

break;

case 8:

case 9:

case 10:

case 12:

case 14:

case 16:

case 17:

mood = "alert";

break;

case 11:

case 15:

mood = "in need of coffee";

break;

case 19:

case 20:

case 21:

mood = "thoughtful";

break;

case 22:

mood = "lethargic";

break;

req.setAttribute( s:"mood", mood);

chain.doFilter(reg,res);

}

@Override

public void destroy() {

}

}

所有当 mood servlet 端真正拿到请求的时候,请求已经被前面所有的 servlet 处理掉,处理之后才能 getattribute 把 mood 取出来。

protected void processRequest(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter();

try{

out.println("<html lang=\"en\">");

out.println("<head>");

out.println("<title>Servlet MoodServlet</title>");

out.println("</head>"); out.println("<body>");

out.println("<h1>Servlet MoodServlet at "

+ request.getContextPath() + "</h1>");

//request.setAttribute("mood","sleepy");

String mood =(String) request.getAttribute( s:"mood");

// String mood =(String)request.getParameter("mood");

//out.println("<p>Duke's mood is: " + mood + "</p >");

if (mood.equals("sleepy")) {

out.println("< img src=\"resources/images/duke.snooze.gif\" alt=\"

} else if (mood.equals("alert")) {

页面显示的是duke vaving

image.png

if (mood.equals("sleepy")) {

out.println("< img src="resources/imaqes/duke.snooze.qif\" alt= "Duke sleeping\"/><br/>")

} else if (mood.equals("alert")) {

out.println("< img src=\"resources/images/duke.waving.gif\" alt=\"Duke waving\"/><br/>");

} else if (mood.equals("hungry")) {

out.println("< img src=\"resources/images/duke.cookies.gif\" alt=\"Duke with cookies\"/><br/>");

} else if (mood.equals("lethargic")) {

out.println("< img src=\"resources/images/duke.handsOnHips. gif\" alt=\"Duke with hands on hips\"/><br,

} else if (mood.equals("thoughtful")) {

out.println("< img src=\"resources/images/duke.pensive.gif\" alt=\"

} else {

out.println("<img src=\"resources/images/duke.thumbsup.gif \" alt=\'}

out.println("</body>");

duke vaving 是 alert 状态。

现在为两点多,获取时间为14为 alert ,一个 filter 和servlet 组合起来做的事情。

request.setAttribute( s: "mood"", o: "sleepy"); 代码打开。虽然现在按照时间来解释14,但是人为的改写一下 mood servlet 里面改写成 sleepy,然后紧跟着获取再观察状态。

request.setAttribute( s: "mood"", o: "sleepy");

// String mood = (String) request.getAttribute( s: "mood");

//out.println(“<p>Dukes mood is:”+mood +“<p>”);

if (mood.equals("sleepy")) {

out.println("< img src="resources/imaqes/duke.snooze.qif\" alt= "Duke sleeping\"/><br/>")

} else if (mood.equals("alert")) {

out.println("< img src=\"resources/images/duke.waving.gif\" alt=\"Duke waving\"/><br/>");

} else if (mood.equals("hungry")) {

out.println("< img src=\"resources/images/duke.cookies.gif\" alt=\"Duke with cookies\"/><br/>");

} else if (mood.equals("lethargic")) {

out.println("< img src=\"resources/images/duke.handsOnHips. gif\" alt=\"Duke with hands on hips\"/><br,

状态:

Servlet MoodServlet at/se122_7_servletsamples_war

image.png

image.png

是想睡着的样子显示 snoode。

再注释掉不从属性里面去获取 mood,从参数里去获取。

// request.setAttribute("mood","sleepy");

// String mood =(String)request.getAttribute("mood");

String mood =(String)request.getParameter(s:“mood");

// out.println("<p>Duke's mood is: " + mood + "</p >");

(mood.equals("sleepy")) {

out.println("< img src=\"resources/images/duke.snooze.gif\" alt=\"Duke sleeping\"/><br/>");

} else if (mood.equals("alert")) {

out.println("< img src=\"resources/images/duke.waving.gif\" alt=\"Duke waving\"/><br/>");

} else if (mood.equals("hungry")) {

out.println("< img src=\"resources/images/duke.cookies.gif\" alt=\"Duke with cookies\"/><br/>");

} else if (mood.equals("lethargic")) {

out.println("< img src=\"resources/images/duke.handsOnHips. gif\" alt=\"Duke with hands on hips\"/><br

结果加参数 mood=hungry

Servlet MoodServlet at/se122_7_servletsamples_war

image.png

image.png

是 hungry 图片。可以看到属性和参数的差异,参数是用户通过 url传递进来的,是指定的东西,可以在里面去得到用户设置的一个东西操作,而属性是后台的代码可以进行操作,无论是 filter 去设置属性还是 servlet get 属性都是在后台做的。就提供前台和后台到底在什么位置去往 request 里面装东西两种不同的途径。这就是我 mood servlet 例子的一个写法。


(4)Filter-to-Servlet Mapping

Filter在监听所有的请求一个 servlet filter,filter 也可以不是所有请求,是其中的某一个比如 /report也可以是 /report 以及 news S1、S2、S3 是最后的真正的 servlet。Servlet 前面可以是一个 filter 或者是两个 filter三个 filter,或者是 F1、F3 两个 filter 构成的链来做处理,filter 过滤中间拦一道做事情,然后把下面的东西给后面的 servlet,filter 不一定是跟 servlet 一对一,从图里可以看出,有些 filter 可以服用往中间去修改一下时间。如果 filter 要决定创建不创建一个 servlet 对象,是生命周期管理,所以一个完整的东西是一个请求过来,先经过 tomcat 配的服务,然后进入 filter,最后进入一个 servlet,这是一个完整的过程,理解了 filter 自然理解 tomcat 配前面的功能:生命周期管理、事务管理,全部都实现以后合起来就叫 Web 容器。它就是按这样的方式来进行处理,容器是一些类似于拦截器一样的东西,帮忙去做一些额外的操作,把自己没有写的但是又必须实现的功能交给 tomcat,tomcat再帮忙来做。

image.png 


6、Handing Servlet Lifecycle Events

Object  Event  Listener Interface and Event

Web  context Initialization and destruction  javax.servlet. ServletContextListener and ServletContextEvent

Web context  Attribute addedremovedor replaced  javax.se rvlet.ServletContextAttributeListener and

ServletContextAttributeEvent

Session Creation, invalidation, activation,passivation,and timeout  javax.servlet.http.HttpSessionListener  javax.servlet. http.HttpSessionActivationListener and HttpSessionEvent

Session  Attribute added,removed,or replaced javax. servlet.ht tp.HttpSessionAttributeListener

and HttpSessionBindingEvent

Request  A servlet request has started being processed by web components  javax.servlet.ServletRequestListener and ServletRequestEvent

Request  Attribute added,removed,or replaced javax.ser vlet.Se rvletRequestAttributeListener and ServletRequestAttrib uteEvent

处理 servlet 的时候,有一些附着在上面的属性,可以来处理 servlet 生命周期的实践。一个 servlet 生命周期不是自己控制,代码里没有出现 new mood servlet 方法代码从来没出现过,完全是由 tomcat 来管理,决定什么时候创建一个对象,什么时候销毁一个对象。所以只能是在生命周期里面可能产生的一系列事件,如果非常感兴趣可以考虑在事件里面去写自己的代码。

@WebListener()

public class SimpleServletListener implements ServletContextL istener,

ServletContextAttributeListener {

static final Logger log=

Logger.getLogger("mood.web.SimpleServletListener");

@Override

public void attributeAdded(ServletContextAttributeEvent event) {

log.log(Level.INFO,"Attribute {0} has been added, with value: {1}",

new Object[]{event.getName(),event.getValue()});

}

@Override

public void attributeRemoved(ServletContextAttributeEvent event) {

log.log(Level.INFo, "Attribute {0} has been removed",

event.getName());

}

@Override

public void attributeReplaced(ServletContextAttributeEvent event) {

log.log(Level.INFo,"Attribute {0} has been replaced, with value: {1}"

new Object[]{event.getName(),event.getValue()});

}

}

简单例子比如写了一个 service context listener,还有 attributelistener 里面会有一些方法比如 attributeadded 当在一个 request 里面再添加一个 attributeadded 的时候就会触发这个方法,在里面可以写自己的逻辑

Listener 在代码实际上也写了,如果产生相应的动作会输出相应的东西,看日志有没有写出来,调的是 log 方法所以不一定在前台显示,可以改成 system tom 方法。会在前台或者后台去显System.out.println("Mood reported:"+event.getValue()); 控制台有输出的原因是用的 system tom,attributeadded 在调 age 方法。

}

@Override

public void attributeAdded(ServletContextAttributeEvent event){

log.log(Level.INFo,msg:"Attribute {0} has been added, with value: {1}",

new Object[]{event.getName(),event.getValue()});

System.out.println("Mood reported:"+event.getValue());

}

@Override

public void attributeRemoved(ServletContextAttributeEvent event){

log.log(Level.INFo, msg:"Attribute {0} has been removed",

event.getName());

}

@Override

public void attributeReplaced(ServletContextAttributeEvent event) {

log.log(Level.INFo,msg:"Attribute {0} has been replaced, with value: {1}",

new Object[]{event.getName(), event.getValue()});

}

}

调 age 方法在 setAttribute 的时候会触发时间,时间触发之后加一行 System.out.println("Mood reported:"+event.getValue()); 代码是为了可以看见输出下面一行。

case 22:

mood = "lethargic";

break;

}

req.setAttribute( s: "mood", mood);

chain.doFilter(req,res);

@Override

public void destroy() {

}

}

所以产生时间可以做相应的处理,如果想做处理要实现 listener,参数什么都没写意味着所有东西全监听,无论往哪个 url 里面写东西全监听,监听到以后全会输出,都执行这些代码事情就出发。


7、HttpRequest Attribute vs. Parameter

HttpRequest Attribute

request.setAttribute("mood", "sleepy");

String mood = (String) request.getAttribute("mood");

http://localhost:8080/ServletMood/report

HttpRequest Parameter

request.setParameter("mood", "sleepy");

or

http://localhost:8080/ServletMood/report?mood=sleepy

String mood = (String) request.getParameter("mood");

总结一下在 request 上面可以去 setAttribute,可以在另外一个代码里 getAttribute,好处是不是来自于一个 url,代码在后台一个 set,一个 get 取出来。刚才演示的 Parameter 是在用户的 url 里面,后面用问号传进来一个参数,mood=sleepy。然后在 request里面可以直接 get 出来 Parameter,也可以在接收到一个请求之后,在 filter 里面塞一个参数方式,也可以在底下去 get 出来,一般约定俗成是在后台代码是最安全的操作,Parameter 专指从前端传递过来的东西。


8、Maintaining Client State

(1)Maintaining Client State

Many applications require that a series ofrequests from a client be associated with one another.

For examplea web application can save the state of a user's shopping cart across requests.

Web-based applications are responsible for maintaining such state,called a session,because HTTP is stateless.

To support applications that need to maintain state,Java Servlet technology provides an API for managing sessions and allows several mechanisms for implementing sessions.

客户端是在传递过来的东西,HTTP 是一个无状态的协议,记不住客户端是谁。


(2)Accessing a Session

不能忘记是通过 http session 对象来维护的,一个 session 的 ID会写回到 cookie 里,每一次都会随 HTTP 请求传递到后台。Sessions are represented by an HttpSession object

You access a session by calling the getsession method of a request object.

This method returns the current session associated with this request; or if the request does not have a sessionthis method creates one.

image.png


(3)Associating Objects with a Session

You can associate object-valued attributes with a session by name.

Such attributes are accessible by any web component that belongs to the same web context and is handling a request that is part of the same session.

HttpSession hs = request.getSession();

Shoppingcart cart = new Shoppingcart();

hs.setAttribute("cart", cart);

cart.add(item);

HttpSession hs = request.getSession();

Shoppingcart cart = hs.getAttribute("cart"):

List<0bject> ls = cart.getItems();

代码 HTTP servlet 里面在 request 上面直接去 getSessionrequest 是 tomcat 去封装的随着快速传递过来 cookie 的东西已经封装好了,在上面 get session的时候能拿封装好的 cookie 里面表示的session id,然后拿 id 到服务器里面找到 HTTP

session 对象,所以直接调 get session 就得到跟当前的用户关联 HTTP 的对象。讲的都是在一个请求上面去加属性,如果是跨多个请求有一个属性要维护就放到 session 里面,在 session 里面比如 session 新创建购物车对象,设到 session 的一个属性,设名字叫cart,然后对象传递的值就是这个对象,在下一次再有请求过来的时候,再在这个请求上 get session 得到 session 对象,把关联的 cart 可以取出来。

在请求 A 里面执行的是HttpSession hs = request.getSession(); Shoppingcart cart = new Shoppingcart(); hs.setAttribute("cart", cart);  代码,在 HTTP session 对象里面放进去的一个 cart,cart 引用到了某一个 cart 对象。

在HttpSession hs = request.getSession();Shoppingcart cart = hs.getAttribute("cart"): List<0bject> ls = cart.getItems();  B 段代码里又获取 session 对象,同一个用户发出来的请求执行这一段代码, get 通过 session,实际上 session 对象没有两个对象,得到 session 对象通过 get cart 可以得到 cart 引用。所以可以在后面继续维护,一个客户发过来 A 请求创建了购物车,发过来 B 请求要求往里面放个东西,B 请求里面的东西会放到 A 请求里创建的购物车里,而不会放到别人创建的购物车里,过程是这样的。具体前面的逻辑说的是怎样做的,后面是代码要怎么写,每一次都在获取跟当前用户相关联的 session,然后对着 session 里的内容操作,可以把多个请求关联一下。


9、Finalizing a Servlet

(1)The web container may determine that a servlet should be removed from service

①for examplewhen a container wants to reclaim memory resources or when it is being shut down.

②In such a casethe container calls the destroy method of

the Servlet interface.

③In this method,you release any resources the servlet is using and save any persistent state.The destroy method releases the database object created in the init method.

(2)A servlet's service methods should all be complete when a servlet is removed.

The server tries to ensure this by calling the destroy method only after all service requests have returned or after a server-specific grace period whichever comes first.

一个 Servlet 尽管不会去管理生命周期,生命周期到底什么时候创建一个对象,什么时候销毁对象从来没管过,但是要写相应的方法,这些方法会被 tomcat 去调用,当 servlet 对象要被销毁的时候,会调 destroy 方法,destroy方法对应的是 init 方法,react 有类似的方法 will mounded 和 did mounded 概念是一样的,在要销毁之前要做什么,在创建之后初始化要做什么,如果 servlet 要操作数据库在 init 里面获取一个数据库连接,在 destroy 里面要把数据库连接释放掉。


10、Uploading Files

(1)Supporting file uploads is a very basic and common requirement for many web applications.


(2)javax.servlet.annotation.MultipartConfig,is used to indic ate that the servlet on which it is declared expects requests to madeusing the multipart/form-data MIME type.

①Servlets that are annotated with @MultipartConfig can retrieve the Part components of a given multipart/form-data request by calling the request.getPart(string name) or request.getParts() method.

(3)multipart/form-data MIME type

①Amethod for uploading files with forms in Browser

②Scenario: the attachment ofan email is attached with formthat is the attachment is uploaded to server in multipart/form-data MIME type

image.png

完整的例子里面剩下的只有 poem 方法,文件没改是通过 maven创建之后里面的东西一个都没有更改。

image.png

唯一的一点问题是如果在机器上把工程加载的时候,可能在 servlet 画红线,按 out 按回车之后会有一个pad Java 16 pandic,选一下下载解压包红线没有,代码会跑。

在课件里面放了另外一个工程,指的是上传一个文件,注意看在本地跑的时候可能会有提示,说 pom 修改要不要引入,一旦引入里面多半就会出错,报错。

image.png

在 progect structure 里面只要是没有创建,会把原级别降掉。

image.png

选一下比如机器上13,选完之后会警告,确认一下。

image.png

再编译不会出错,编译成功。

例子非常简单,只有一个 servlet ,要上传一个文件,doget、dopost 调用方法。

@webServlet(name =“FileUploadServlet",urlPatterns ={"/upl oad"})

MultipartConfig

public class FileUploadServlet extends HttpServlet {

private final static Logger LOGGER =

Logger.getLogger(FileUploadServlet.class.getCanonicalName());

protected void processRequest(HttpServletRequest request,

HttpServletResponse response)

throws ServletException,IOException {

response.setContentType("text/html;charset=UTF-8");

// Create path components to save the file

final String path =request.getParameter(s:"destination');

final Part filePart = request.getPart(s:"file");

final String fileName=getFileName(filePart);

OutputStream out=null;

InputStream filecontent = null;

final PrintWriter writer=response.getWriter();

try {

out =new FileOutputStream(new File( pathname path +File.separator

+fileName));

filecontent=filePart.getInputStream();

int read =0;

final byte[] bytes=newbyte[1024];

while ((read =filecontent.read(bytes))!= -1) {

out.write(bytes, off:0. read);

}

writer.println("New file " + fileName + " created at " + path);

LOGGER.log(Level.INFo,msg: "File{0}being uploaded to {1}",

new Object[]{fileName, path});

} catch (FileNotFoundException fne){

writer.println("You either did not specify a file to upload or are "

+"trying to upload a file to a protected or nonexistent “+ "location.");

writer.println("<br/> ERROR: " + fne.getMessage());

LOGGER.log(Level.SEVERE, msg:"Problems during file upload. Error: {e}",

new Object[]{fne.getMessage()});

} finally{

if (out != null) {

out.close();

}

If(writer != null) {

writer.close);

}

}

}

private String getFileName(final Part part) {

final String partHeader=part.getHeader(s:"content-disposit ion");

LOGGER.log(Level.INFo,msg:"Part Header={8}",partHeader);

for (string content :part.getHeader(s:"content-disposition").s plit( regex: "."))

if (content.trim().startsWith("filename")) {

return content.substring(

content.index0f('=') + 1).trim().replace( target: "\"", replace ment: “*);

}

}

return null;

}

/**

* Handles the HTTP <code>GET</code> method.

*

* @param request servlet request

* @param response servlet response

* @throws ServletException if a servlet-specific error occurs

* @throws I0Exception if an 1/0 error occurs

*/

@Override

protected void doGet(HttpServletRequest request,HttpServlet Response response)

throws ServletException, IOException {

response.setContentType("text/html;charset=UTF-8"); processRequest(request,response);

}

/**

* Handles the HTTP <code>POST</code> method.

*

*@param request servlet request* eparam response servlet response

* @throws ServletException if a servlet-specific error occurs

* @throws I0Exception if an 1/0 error occurs

*/

@Override

protected void doPost(HttpServletRequest request,HttpServle tResponse response)

Throws ServletException,IOException{

processRequest(request,response);

}

/**

* Returns a short description of the servlet.

*

* @return a String containing servlet description

*/

@Override

public String getServletInfo(){ return "Short description"; }// </editor-fold>

}

有一个界面

<!DOCTYPE html>

<html lang="en">

<head>

<title>File Upload</title>

<meta http-equiv="Content-Type" content="text/html; charset =UTF-8">

</head><body>

<form method="POST" action="upload" enctype="multipart/f orm-data">

File:

<input type="file" name="file" id="file" /> <br/>

Destination:

<input type="text" value="/tmp" name="destination"/>

</br>

<input type="submit" value="Upload" name="upload" id="upload" />

</form>

</body>

</html>

按 post 的方法来传递,产生一个 upload 请求,里面会有 file 要有一个文本框,输入文件在哪里,然后输出到哪里,file 是一个文件选择框,选好一个文件之后说放到哪里,如果没有选默认是 tmp,然后点 upload submit 按钮,就会产生请求去上传。

例子跑起来,读取文件随便选一个

File: 选择文件 chat.txt

Destination: /tmpi

Upload

选 upload 上传:

New file chat.txt created at /tmp

新文件在目录中上传。

当 Mac 的机器再登陆一下

image.png

Chat.txt 已经上传上去。

上传的方法实现

传文件在前面加一个 MultipartConfig 的 Allocation,一个文件可能会很大会切分成很多小的包上传,一旦要传文件上去,文件可能会比较大,用到前面的 servlet 在设置内容类型的时候,要设置成刚才看到的可以分成若干个 part 上传的类型。


(4)The @MultipartConfig annotation supports the following optional attributes:

① location:

An absolute path to a directory on the file system.

The default location is "".

②fileSizeThreshold:

The file size in bytes after which the file will be temporarily stored on disk.

The default size is 0 bytes.

③MaxFileSize:

The maximum size allowed for uploaded files in bytes.

If the size of any uploaded file is greater than this sizethe web container will throw an exception(IllegalStateException).

The default size is unlimited.

④maxRequestSize:

The maximum size allowed for a multipart/form-data reguest in bytes.

The web container will throw an exception if the overall size of all uploaded files exceeds this threshold.

The default size is unlimited.

需要加一个 annotation, annotation 第一个是路径,文件系统绝对路径是什么,要去上传下载那个路径,实际上一般缺省值是空的,要去设置一下。结合例子怎么设,有一个文件的尺寸的阀值,一个门限值,意思是上传接收到之后在服务器的内存里面,只要大于这个值,就存到硬盘上去,暂时先存到硬盘上,缓存一下最后完整的文件,再往一个指定的位置去写,缺省情况是零,接收到应该在硬盘上暂存一下,文件最大的尺寸是一次可以上传多个文件,所有这文件合起来的总尺寸是多大。


(5)Uploading Files

①For,examplethe @MultipartConfig annotation could be constructed as follows:

@MultipartConfig(location="/tmp",

filesizeThreshold=1024*1024,

maxFilesize=1024*1024*5,

maxRequestsize=1024*1024*5*5)

②Instead of using the @MultipartConfig annotation to hard-codethese attributes in your file upload servlet,you could add the following as a child element of the servlet configuration element in the web.xml file.

<multipart-config>

<location>/tmp</location>

<max-file-size>20848820</max-file-size>

<max-request-size>418018841</max-request-size>

<file-size-threshold>1048576</file-size-threshold>

</multipart-config>

例子是在 tmp 里面去传文件,只要大于 1024*1024 就要文件到硬盘系统里去暂存一下,然后文件最大是允许同时传五个文件,所以整个总的文件大小是 1024*1024*5。如果不用 annotation 要告诉 tomcat web 控件希望怎样管理。一种是 annotation ,一种是 xml,如果用 annotation 在代码里直接写,用 xml 要在 web.xml 资料文件里写,这个文件在 webapp 目录下面的 webinf 目录里面写,文件的内容特别多要详细去讲要花很多时间。告诉 tomcat 每个 servlet 都是什么,会监听什么样的 url,作用完全可以用 annotation  来替代。

③The Servlet specification supports two

additional HttpServletRequestmethods

Collection<Part> getParts()

Part getPart(String name)

④The javax.servlet.http.Part interface is a simple oneprov iding methods that allow introspection of each PartThe methods do the following

Retrieve the namesizeand content-type of the Part

Query the headers submitted with a Part

Delete a Part

Write a Part out to disk

两种方式相比的优缺点。在 HttpServletRequest 里可以通过 get paths 和 get path 分别去获取一个文件,不是有药可能要分很多部分吗,他所有的部分以及具体的某一个部分。因为要把一个文件切分成很多块去传,这个方法实际上在例子里面不是很有用。

⑤Index.html

<!DOCTYPE html>

<html lang="en">

<head>

<title>File Upload</title>

<meta http-equiv="Content-Type" content="text/html; char set=UTF-8">

</head>

<body>

<form method="POST" action="upload" enctype="multipart/ form-data" >

File:

<input type="file" name="file" id="file" /> <br/>

Destination:

<input type="text" value="/tmp" name="destination"/>

</br>

<input type="submit" value="Upload" name="upload" id=" upload" />

</form>

</body>

</html>

Form 有 post,之后会产生一个 upload 请求,内容是multipart/ form-data。

⑥FileUploadServlet.java

@WebServlet(name ="FileUploadServlet",urlPatterns = {"/uplo ad"})

@MultipartConfig

public class FileUploadServlet extends HttpServlet {

private final static Logger LOGGER =

Logger.getLogger(FileUploadServlet.class.getCanonicalName());

protected void processRequest(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

response.setcontentType("text/html;charset=UTF-8");

// Create path components to save the file

final string path = request.getParameter("destination");

final Part filePart = request.getPart("file");

final string fileName = getFileName(filePart);

Outputstream out = null;

Inputstream filecontent = null:

final PrintWriter writer = response.getWriter();

在 Servlet 要写首先前面 servlet 监听的 url 是 upload,和页面里的 upload 匹配起来了。有 @MultipartConfig 全部用的默认值,没有去做任何修改,所以加一个它就跟,把它删了除是不行的必须要有。

下面有 process request,返回去的页面 New file chat.txt created at /tmp,页面本身没有什么文本,是在浏览器一端要把请求和文件一起传给服务器端,所以在浏览器内一端说的编码器主要是

multipart/ form-data,upload 请求发出来的,内容类型给multipart/ form-data。再往下看有 destination,有 file 两个东西 Post 过来就变成了它的参数,所以在 FileUploadServlet.java

里面在上面去获取参数 express destination,destination 是直接参数,file 因为传过来的是 multipart,里面调一下就完成,get part file 得到一个 part 类型的表示文件名的一个东西,毕竟是 part 类型,所以自己要写一个叫 get file name 的东西,把它转成文件名。

FileUploadServlet.java

private String getfileName(final Part part) {

final string partHeader =part.getHeader("content-dispositi on");

LOGGER.log(Level.INFO,"Part Header = {0}",partHeader);

for (String content :part.getHeader("content-disposition").s plit(";")) {

if(content.trim().startsWith("filename")){

return content.substring(

content.indexOf('=') + 1).trim().replace("\"","");

}

}

return null;

)

@Override

protected void doGet(HttpServletRequest request, HttpServlet Response response)

throws ServletException, IOException {

processRequest(request, response);}

@Override

protected void dopost(HttpServletRequest request, HttpServlet Response response)

throws ServletException, IOException {

processRequest(request,response);

}

}

转文件名的方法是给一个 part 之后,然后要去读取 part 里面content disposition 文件的相关内容,可以支持多个文件上传吗?多个文件上传每个文件名字分号分开,所以要把分号隔开,里面每一个 ; 都是一个文件,对于里面的每一个文件把前面和后面的名字空格都删掉,里面名字格式是 filename=... ,以 filename 开头里面写的 filename=... 是第一个文件,file name=... 是第二个文件用分号隔开。取 = 从 = 位置往后的一个位置开始的这一段出来,出来之后同样在把前面空的和把后面空的空格删掉,然后把里面所有的 / 路径全部替换掉,要得到具体的名字,后面细节return content.substring( content.indexOf('=') + 1).trim().replace(" \"",""); 语句不是特别重要,前面可以看出来一次性可以上传多个文件,文件是用分号隔开,而且写的是 filename=...; filename=...;

之后剩下的东西以看到跟前面类似,要接收一个请求,然后发送一个出去读到文件然后文件要输出,输出上传的文件产生输入把文件读进来,然后写出到指定的地方去,下面是文件的操作。Servlet dopost 方法过来,所以 post 刚才写的方法就完成了一次上传

image.png

真正在执行的东西。

可以在代码的前面 annotation 的方式表示,也可以把东西全部集中在 web.xml 里面去。用 annotation 的好处是每一个标志它作用于谁一目了然,很清楚要干什么把所有内容全部提取出来写到一个文件里。它的缺点是还要再到具体的文件里去看每一个文件的代码对应起来看看好处是如果要修改是集中在一个文件里修改,不用到处都安装配置,想改东西要到哪个文件里去改两种方式都可以,但是普遍倾向于 annotation,例子基本上没有用 xml 做配置,全部都是用 annotation 来写。这就是使用 annotation 和 xml 的差异。


11、References

(1)The Java EE 8 Tutorial-Distributed MultitieredApplications

https://javaee.github.io/tutorial/overview004.html#BNAAY

(2)The Java EE 8 Tutorial-Java Servlet Technology

ttps://javaee.github.io/tutorial/servlets.html#BNAFD

(3)Java Servlet Specification

http://download.oracle.com/otn-pub/jcp/servlet-3_1-fr-eval

spec/servlet-3_1-

final.pdf?AuthParam=1396178605_99ca893c1d2485541a2baf6a88414 bf8

实际上后面不会用 servlet 来写,无论是 spring 的 controller 还是 struts 的 action 都是对 servlet 的一个封装,必须要了解 servlet,要知道道理是什么,知道之后去看 controller、action才知道是怎么实现的,是一个封装基本的道理是要知道每一个 web servlet 或者是 controller 或者是 action 都要去监听某一个类型的 url,某一种模式的url。里面有 doget 、dopost 的方法,处理同一个 url 的请求过来有 get 有 post 有put 有deliet 等等,针对不同的方法有不同的处理机制,除了这两点没有其他任何东西。Request、response 要记住都是 tomcat 封装的拿来直接给,在 controller 和 action 里面也是同样的道理,所以明白 servlet 工作原理再谈 spring 和 struts 工具的时候会变得比较简单。

在运行项目的时候出现错报,是点错出来的一个很奇怪的异常,看到的异常未必是真正的问题。刚才用 maven 之后改成13,选的时候没注意选成 13 preview,再去跑服务的时候报错。点成 13 preview之后去部署的时候就会报错。

看不出来能说明什么,一个或多个间定期失败,虽然都是13,选择的 preview。

image.png

选回到 13 就又好了,是 JDK 的版本问题,但暴露出来的错误异常不能直接发现。

 

image.png

如果把异常结出来非常的不直观,很难判断是什么原因。

相关文章
|
1月前
|
Java 容器
【学习笔记】Jsp与Servlet技术
【学习笔记】Jsp与Servlet技术
61 0
|
6月前
|
网络协议 前端开发 Java
异步Servlet学习笔记(一)
异步Servlet学习笔记(一)
|
XML 存储 前端开发
Servlet技术入门(视频学习笔记)-2
2、ServletContext类的四大作用 获取web.xml中配置的上下文参数context-param 获取当前工程路径,格式:/工程路径 获取工程部署在服务器硬盘上的绝对路径
|
小程序 Java 应用服务中间件
Servlet技术入门(视频学习笔记)-1
一、Servlet技术 1、什么是Servlet Servlet是JaveEE规范之一,规范就是接口 Servlet是JavaWeb三大组件之一。三大组件分别是:Servlet程序、Filter过滤器、Listener监听器 Servlet是运行在服务器上的一个java小程序,它可以接收客户端发送来的请求,并响应数据给客户端
|
API
java202304java学习笔记第六十二天-ssm-获取servlet相关api
java202304java学习笔记第六十二天-ssm-获取servlet相关api
76 0
|
API
java202304java学习笔记第六十二天-ssm-获取servlet相关api
java202304java学习笔记第六十二天-ssm-获取servlet相关api
92 0
|
前端开发 Java 应用服务中间件
Servlet入门学习笔记(下)
Servlet入门学习笔记(下)
|
前端开发 Java 关系型数据库
Servlet入门学习笔记(上)
Servlet入门学习笔记(上)
108 0
|
开发者
Servlet 之接口的介绍以及实现 Servlet 接口 | 学习笔记
快速学习 Servlet 之接口的介绍以及实现 Servlet 接口。
117 0
Servlet 之接口的介绍以及实现 Servlet 接口 | 学习笔记
|
数据处理 开发者
Servlet 相关类之 ServletRequest 和 Servletresponse 对象的简单介绍 | 学习笔记
快速学习 Servlet 相关类之 ServletRequest 和 Servletresponse 对象的简单介绍。
Servlet 相关类之 ServletRequest 和 Servletresponse 对象的简单介绍 | 学习笔记