ハードウェアとソフトウェアを含め、リクエストを処理し、応答を返すすべての要素のセット全体をサーバーと呼びます。
リクエストを処理し、応答するときにサーバーが従う原則。
サーバーアプレットはサーバー側で実行される Java アプリケーションであり、Java 言語で書かれており、サーブレット仕様の中核である Java 仕様に準拠しています。
サーブレットは Web サーバー全体のコントローラーとして機能し、対応するビジネス ロジック処理にリクエストを転送します。
Tomcat は、サーブレット仕様と JSP 仕様を実装したコンテナであり、Apache によって提供される、無料の軽量な レベルのアプリケーション サーバーです。中規模のシステムと同時アクセス ユーザーの場合はあまり多くありません。
多目的インターネットメール拡張プロトコルである MultiPurpose Internet Mail Extensions は、ファイルの受信後にブラウザが対応するコンポーネントを呼び出して開くことができるように、ファイルの種類ごとに仕様を開発します。
2つの重要なクラスレベル効果。
ServletContext のスコープから見てみましょう。
servletContext.setAttribute(name, object);//向servletContext作用域中添加属性,该属性为所有用户共享servletContext.getAttribute(name);//获取servletContext作用域中指定属性的属性值servletContext.removeAttribute(name);//从servletContext作用域中删除指定属性servletContext.getRealPath(path);//根据相对于项目的路径获取资源的绝对路径URLservletContext.getResourceAsStream(path);//获取路径文件的输入流servletContext.getInitParameter(name);//获取初始化参数的值
入手方法があります。
this.getServletContext();//HttpServlet提供了获取ServletContext实例对象的方法,在doGet或者doPost方法内部request.getServletContext();//通过request对象获取HttpSession session = request.getSession(); session.getServletContext();//通过session对象获取
りー
Web容器启动时会创建两个与Servlet相关的Map集合,两个集合的key值均为urlPattern,即请求uri,第一个Map的value是Servlet的引用变量,第二个Map的value是Servlet的全限定性类名。请求到达Web容器后,系统先搜索第一个Map集合,如果存在与uri对应的引用变量,则获取该引用变量,如果不存在,继续搜索第二个Map集合,获取对应的全限定类型,创建对象,并把引用变量存到第一个Map集合中。
Servlet ServletConfig Serializable
| | |
--------------------------------------------------
|
|
Servlet接口是Servlet规范中定义的,服务器自动调用其中service方法处理请求,该接口有多个抽象方法,很多在实际开发中很少使用,实现该接口需要实现其中的全部抽象方法,因此不采用直接实现Servlet接口的方法创建Servlet。
GenericServlet实现Servlet接口中大多数抽象方法,保留了一个抽象方法service,继承该抽象类创建servlet,必须实现该抽象方法。HTTP中多个请求方法在处理请求前必须做一些固定的前置工作,如果实现该serivce方法就需要在每一个Servlet的service方法中都编写前置工作代码,造成代码冗余。为了解决此问题,tomcat提供了一个GenericServlet的子类HttpServlet,HttpServlet采用固定行为结构的模板方法模式将前置工作固定在一个方法,用户在创建Serlvet时继承HttpServlet,然后重写与请求方式对应的方法即可。(具体参考源码)
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { String method = req.getMethod();if (method.equals(METHOD_GET)) {long lastModified = getLastModified(req);if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logic doGet(req, resp); } else {long ifModifiedSince;try { ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) {// Invalid date header - proceed as if none was setifModifiedSince = -1; }if (ifModifiedSince < (lastModified / 1000 * 1000)) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else {//// Note that this means NO servlet supports whatever// method was requested, anywhere on this server.//String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }
从中可以看出Get请求在实际执行前做了很多准备工作。
Servlet默认在调用时创建并初始化,这也是工作原理中第一个Map集合引用变量为空情况出现的原因。对一些必定会被访问并且访问频繁的Servlet可以设定为在容器启动时创建并初始化,提高访问速度。
<load-on-startup>int类型数字</load-on-startup>
小于0:默认值,调用时创建初始化。
等于大于0:在Web服务器启动时创建初始化,值越小,优先级越高。出现相同值时,不会出现异常,容器自定义顺序执行。
this.getInitParameter("");//获取初始化参数this.getServletName();//获取配置文件<servlet-name>标签的内容this.getServletContext();
6.由于继承HttpServlet创建的Servlet属于自定义类,系统不知晓,必须在配置文件中配置:
<servlet> <servlet-name>bothRegisterServlet</servlet-name> <servlet-class>com.servlet.register.BothRegisterServlet</servlet-class> <init-param> <param-name>xxx</param-name> <param-value>xxxx</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported></servlet><servlet-mapping> <servlet-name>bothRegisterServlet</servlet-name> <url-pattern>/bothRegisterServlet01</url-pattern></servlet-mapping>
Webコンテナ内のサーブレットオブジェクトにアクセスする場合は、どの方法を使っても間接的にしかアクセスできないため、一般的にURLを使用してサーブレットにアクセスするため、1対1の関係を確立する必要があります。アクセス時に使用される URL と最終的なリソース サーブレットの間のマッピング関係が、servletMapping が存在する理由です。
サーブレット オブジェクトに対して複数の URL 形式を設定できるようにします。
4つのリクエスト2. リクエストにはどのような情報が含まれますか?またはリクエストを通じてどのような情報が取得できますか?
3. 共通メソッド:
getAttribute: スコープ内の属性を取得します。属性が存在しない場合は、null が返されます。
⑵ request.getSession() と request.getSession(boolean create) の比較
getSession(false): Cookie に基づいて Session オブジェクトを取得します。Cookie が存在しない場合は、null を返します。
⑶request.setCharacterEncoding(): リクエスト本文のエンコード方式、つまりサーバーがブラウザーによって送信されたデータを解析するときに使用されるエンコード方式を設定します。
⑷request.getContentLength(): リクエスト本文のバイト長を取得します。POST でのみ意味があります。
⑸request.getQueryString(): URL の後のリクエスト文字列を取得します。これは GET リクエストでのみ意味を持ちます。
⑹request.getRequestDispatcher().forward(request,response)request.getRequestDispatcher().include(request,response)の違い:
forward リクエストは引き続き前進し、応答権は後続のリソースに転送されます。サーバー自体に応答することはできません。つまり、サーバー自体で out.write
include インクルードでは、次のリソースをそれ自体の一部として扱います。次のリソースが応答できるだけでなく、それ自体も応答できます。これは、独自のコードの一部を次のリソースに分割するのと同等です。
4. 同じリクエストとは何ですか?
同一リクエストはスコープ内のリクエストパラメータや属性などの情報を共有します。
Servlet规范定义的一个向浏览器发出响应的对象,由Servlet容器自动创建。
由于存在多种响应数据类型,因此服务器在响应前必须指明数据类型,以便浏览器根据指定类型处理接收的数据。
response.setContentType("text/html;charset=UTF-8");//以HTML方式处理
response.setHeader(name,value);
response.addCookie(Cookie cookie);
response.sendRedirect(url);
PrintWriter out=reponse.getWriter();
ServletOutputStream sos=response.getOutputStream();
代码继续执行,对响应结果或者request作用域没有影响,因为响应已经结束,请求已转发给其他资源,自身就失去了处理请求的能力,但对session\applicatiion作用域可以产生影响。通常不在响应或者跳转之后对整个处理过程施加影响。
由服务器生成,保存在浏览器端的存储会话信息的对象。
Servlet规范提供了Cookie类,用于创建Cookie对象:
Cookie cookie=new Cookie(name,value);
由服务器创建,保存在客户端,浏览必须允许保存Cookie将cookie:
response.addCookie(cookie);
Cookie在访问服务器时自动提交,这种提交不是无选择地对任何访问路径都提交,而是只对设定的路径提交。在未单独设定Cookie的绑定路径时,Cookie与生成Cookie的访问路径绑定,访问该路径下任何一个资源时,浏览器自动提交Cookie。
可以设定Cookie的绑定路径,使Cookie不受生成路径的限制:
cookie.setPath(String uri);
默认情况下,Cookie保存在浏览器缓存中,浏览器关闭,Cookie销毁。如果希望Cookie中保存的信息长期存在,可以将Cookie保存到本地硬盘中,前提是当前浏览器支持。
cookie.setMaxAge(int expiry);//以秒为单位
取值大于0:将Cookie保存到硬盘中,无论浏览器是否关闭,指定时长过去后,Cookie被销毁。
等于0:立即销毁Cookie。
小于0:默认情况,将Cookie保存在浏览器缓存中,浏览器关闭,Cookie销毁。
String name = cookie.getName();//获取Cookie的名称String value = cookie.getValue();//获取Cookie的值cookie.setValue(newValue);//修改Cookie的值
Cookie主要用于保存浏览器关闭以后需要保留的会话信息,如登陆信息,实现免登陆功能。
在HTTP协议中,浏览器向服务器发送请求,服务器响应完毕后,连接结束,服务器端没有保存本次请求的任何信息,这就是HTTP协议的无状态特性。如果需要保存会话信息,就必须提供一种解决方案,而Session就是这个解决方案。
Session是用来在服务器端保存会话信息的对象,比如保存用户在网站上的足迹等。
在浏览器开启Cookie的情况下,从浏览器第一个访问网站到浏览器关闭的时间内浏览器与服务器所有的互动都是在同一个会话中。如果浏览器关闭了Cookie,那么浏览器每向服务器发送一次请求,都开启一个新的会话,即服务器端都会新建一个Session对象。
第一次访问时,服务器会自动创建一个Session对象,并为Session对象分配一个唯一的32位的id,同时生成一个Cookie对象,name为JSESSIONID,value为Session的id。在Cookie的有效期内,再次访问服务器时,根据value值获取对应的Session对象,这样就保证了在同一次会话中存在的始终是同一个Session对象。
Session对象在浏览器第一次访问服务器时创建,如果浏览器长时间不向服务器发送请求,在指定的时长之后,服务器会销毁Session对象。
这里所说的时长不是从Session创建到销毁的时间长度,而是浏览器长时间发送请求,服务器保存Session对象的最大时间长度,通过以下方法设置,以秒为单位:
session.setMaxInactiveInterval(int interval);
通过以下方法,浏览器可以主动销毁Session对象:
session.invalidate();
Session主要用于在同一会话中共享数据,所以对Session的主要操作是操作作用域中的属性:
session.setAttribute(name,value);//向作用域中添加属性session.getAttribute(name);//获取作用域中的属性session.removeAttribute(name);//从作用域中删除属性
服务器接收到请求以后,首先对请求进行预处理,然后将请求转发给其他的资源继续处理,这种转发叫做请求转发。
服务器调用特定的方法向浏览器发送一个资源路径,浏览器访问该路径,这一过程叫做重定向。
请求转发是服务器调用不同的资源处理同一请求,始终是同一请求。
重定向使得浏览器再次向服务器发送请求,前后是两个不同的请求。
为耗时的任务分配一个线程,主线程继续执行后面的代码,执行完毕,将主线程归还线程池,以便执行其他的请求。
Servlet是单例多线程的,允许并发访问的线程数目有限,为此Servlet建立了一个线程池,请求必须从线程池中获取了线程才能访问Servlet。若一个请求长时间占有线程,可能导致后面的请求长时间等待,降低了程序的吞吐能力。如果一个线程从Servlet线程池中获取了线程以后,另外开启一个线程处理耗时的任务,及时将主线程归还线程池,就解决这个问题。
异步机制的作用主要不是为了提高单次执行速度,而是提高吞吐量,即同一时间段内允许更多的请求访问Servlet。为了提高访问的线程数目,降低每次访问占有Servlet线程的时间,将耗时的任何交个另外一个线程处理,将主线程及时归还线程池。
Servlet接收到请求以后,对请求进行初步处理,然后开启一个异步线程处理具体的业务,Servlet线程继续执行后面的代码,执行完毕后,将Servlet线程归还线程池,以便其他请求使用。等待异步线程执行完毕后一起响应,异步线程执行完毕主要有两个标志:
在异步线程内部调用complete方法。
超时时间结束。
超时时间不并代表异步线程的生命时长,而是最大生命时长。如果在超时时长内,异步线程调用了complete方法,异步线程提前结束。
异步线程默认的超时时长是10s(Servlet不同版本不同),当主线程执行完毕,同时超时时长结束或者异步线程提前结束,服务器开始向浏览器发送响应,销毁request、response对象,关闭输出流,如果异步线程未执行完毕,那么异步线程中已执行的响应会响应到浏览器,未执行的响应不会响应到浏览器。
分配给异步线程的时间不是无限的,因此存在一个响应时机的问题。
在主线程执行完毕并且异步线程超时时长用完或者提前结束时响应。
AsyncContext ac=request.startAsync(); ac.setTimeout(int mills); ac.start(Runnable run);//将异步线程管理对象ac作为参数传入异步线程中,通过该参数可以获取request\response
由于异步机制的设计目的是为了使请求尽快归还Servlet线程,提高程序的吞吐量,并未显著提高响应速度。异步机制通常不直接用作向浏览器输出响应内容,如在异步线程内部使用out.write直接向浏览器输出,而是用来处理耗时的任务,将处理结果存放到session/application等作用域中。
8.还可以使用AsyncContext对象为异步线程添加监听器,监听异步线程的执行过程。
1.配置Servlet、Filter、Listener、contextParams等构成应用程序的重要信息。
<welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>default.html</welcome-file></welcome-file-list>
注:在配置文件中书写路径时,只有欢迎列表中的路径不需要在前面加“/”,其他地方的路径都需要在前面加“/”,因为欢迎页面只能放在WebContent根路径下,不能放在WebContent根路径下的文件夹内,其路径相对固定,因此可以简写。
<error-page> <error-code>404</error-code> <location>/xxxx</location>//可以放在WebContent目录下任意位置</error-page>
<error-page> <exception-type>java.lang.NullException</exception>//异常类必须写完整的类名 <location>/xxxx</location></error-page>
<context-param><param-name>paramName</param-name><param-value>paramValue</param-value></context-param>
Servlet3.0新增注解式开发,注解式开发就是将在编写在配置文件web.xml中的信息转移到类文件上。
注解方式:
在类名上添加注解:
@WebServlet(urlPatterns={"",""},loadOnStartup=1,initParams={@WebInitParam(name="",value="")},asyncSupported=true)
两种注册方式同时存在,如果映射路径不相同,相当于存在一个集中了所用路径的Servlet,如果存在相同路径,服务器无法启动。
1.Servlet3.0提供一个Part类型,该类封装了上传文件信息。
2.文件名存储在一个名为Content-Disposition的请求头中。
Part part=request.getPart(文件字段名);//获取文件封装对象String fileName=part.getHeader("Content-Dispostion");//获取文件名part.write("parentPath/"+fileName);//将文件保存到指定路径,只能使用绝路径
1.Servlet提供了ServletOutputStream用作文件下载的输出流。
2.文件下载时必须设置浏览器以附件的形式处理从服务器获取的数据:
response.setHeader("Content-disposition","attachment;filename=xxxx");
如果请求头中设置的文件名含有中文必须转化为ISO-8859-1的编码方式。
3.从服务器获取输入流,利用ServletOutputStream输出流将文件写到用户指定路径:
InputStream is = getServletContext().getResourceAsStream("/Files/upload.txt"); ServletOutputStream os = response.getOutputStream();
入力ストリームと出力ストリームの場合、後続の操作は入力ストリームの内容を出力ストリームに書き込むことであり、これは一般的な IO 操作です。
サーブレットはシングルトンの形式でマルチスレッド環境で実行され、インスタンス変数はヒープ内のオブジェクトに格納されます、ヒープは複数のスレッドによって共有されるため、インスタンス 変数にはスレッド セーフティの問題があり、静的変数はメソッド領域に格納され、これも複数のスレッドによって共有され、ローカル にも問題があります。面を変えるストレージ スタックでは、スタック内のデータは内部で共有され、スタック間では共有されません。つまり、1 つのスレッドに 1 つのスタックがあるため、ローカル変数はスレッドセーフです。
グローバル変数をローカル変数に変換します。
グローバル変数を変更するコードを同期メソッドまたは同期ブロックに追加します。
グローバル変数を ThrrealLocal に保存し、変数のコピーを各スレッドに割り当てます。各スレッドは互いに独立して動作します。
オープンリソース:はい 使用されるリソースは公開されており、許可なくアクセスできます。
許可リソース: ユーザーの個人情報を保存し、本人確認後にのみアクセスできるリソース。
一度ウェブサイトにログインすると、次回同じブラウザでウェブサイトにアクセスする際に再度ログインする必要はありません。
ログイン情報(ユーザー名、パスワード)をCookieに保存し、ローカルに保存し、Webサイト訪問時に自動的にCookieを送信し、フィルターを通過させます。 または Interceptor 認証に合格すると、ログインせずに直接アクセスできます。
同じブラウザ: ローカルで Cookie オブジェクト検証情報を取得するためにログインは不要です。
Servlet3.0 コンポーネントはチェック可能です。これは、サーブレット、フィルター、およびリスナーをシェルフ パッケージとしてプロジェクトに挿入できることを意味します。
プロジェクトWebフラグメントプロジェクトを作成します。
パッケージjarファイル。
libディレクトリに置いてラックパッケージとして使用します。
一般的に使用されるいくつかのサーブレットコンポーネントをラックパッケージにカプセル化し、それらを lib ディレクトリに直接配置して使用できます (POST リクエストの中国語の文字化けを解決するためのフィルターなど)。
Web の実行中にサーブレット、フィルター、リスナーを登録します。
セキュリティ上の理由から、Web サーバーの起動時、つまり ServletContextListener リスナーを通じてのみ登録できます。
以上がサーブレットの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。