关于servlet:HttpServletResponse介绍及应用

web服务器接管到客户端http申请,针对这个申请,别离创立一个代表申请的HttpServletRequest对象,代表响应的一个HttpServletResponse; 如果要获取客户端申请过去的参数:找HttpServletRequest如果要给客户端响应一些信息:找HttpServletResponse1、简略分类负责向浏览器发送数据的办法 ServletOutputStream getOutputStream() throws IOException; PrintWriter getWriter() throws IOException;负责向浏览器发送响应头的办法 void setCharacterEncoding(String var1); void setContentLength(int var1); void setContentLengthLong(long var1); void setContentType(String var1); void setDateHeader(String var1, long var2); void addDateHeader(String var1, long var2); void setHeader(String var1, String var2); void addHeader(String var1, String var2); void setIntHeader(String var1, int var2); void addIntHeader(String var1, int var2);响应的状态码 int SC_CONTINUE = 100; int SC_SWITCHING_PROTOCOLS = 101; int SC_OK = 200; int SC_CREATED = 201; int SC_ACCEPTED = 202; int SC_NON_AUTHORITATIVE_INFORMATION = 203; int SC_NO_CONTENT = 204; int SC_RESET_CONTENT = 205; int SC_PARTIAL_CONTENT = 206; int SC_MULTIPLE_CHOICES = 300; int SC_MOVED_PERMANENTLY = 301; int SC_MOVED_TEMPORARILY = 302; int SC_FOUND = 302; int SC_SEE_OTHER = 303; int SC_NOT_MODIFIED = 304; int SC_USE_PROXY = 305; int SC_TEMPORARY_REDIRECT = 307; int SC_BAD_REQUEST = 400; int SC_UNAUTHORIZED = 401; int SC_PAYMENT_REQUIRED = 402; int SC_FORBIDDEN = 403; int SC_NOT_FOUND = 404; int SC_METHOD_NOT_ALLOWED = 405; int SC_NOT_ACCEPTABLE = 406; int SC_PROXY_AUTHENTICATION_REQUIRED = 407; int SC_REQUEST_TIMEOUT = 408; int SC_CONFLICT = 409; int SC_GONE = 410; int SC_LENGTH_REQUIRED = 411; int SC_PRECONDITION_FAILED = 412; int SC_REQUEST_ENTITY_TOO_LARGE = 413; int SC_REQUEST_URI_TOO_LONG = 414; int SC_UNSUPPORTED_MEDIA_TYPE = 415; int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; int SC_EXPECTATION_FAILED = 417; int SC_INTERNAL_SERVER_ERROR = 500; int SC_NOT_IMPLEMENTED = 501; int SC_BAD_GATEWAY = 502; int SC_SERVICE_UNAVAILABLE = 503; int SC_GATEWAY_TIMEOUT = 504; int SC_HTTP_VERSION_NOT_SUPPORTED = 505;1.1、常见利用1、向浏览器输入音讯2、下载文件1)要获取下载文件的门路2)下载的文件名是啥?3)设置想方法让浏览器可能反对下载咱们须要的货色4)获取下载文件的输出流5)创立缓冲区6)获取输入流对象 7)将FileOutputStream流写入到buffer缓冲区8)应用OutputStream将缓冲区中的数据输入到客户端! ...

June 11, 2021 · 2 min · jiezi

关于servlet:对HttpServletRequest中的Header进行增删

HttpServletRequest 没有提供批改/删除的ApiHttpServletRequest中定义的对Header的操作全是只读,没有批改。 public interface HttpServletRequest extends ServletRequest { ... public long getDateHeader(String name); public String getHeader(String name); public Enumeration<String> getHeaders(String name); public Enumeration<String> getHeaderNames(); public int getIntHeader(String name); ...}HttpServletRequest 只是一个接口,实现由Servlet容器提供。不论是任何容器,实现类,必定是要把申请的Header存储在某个中央,于是能够通过反射来对存储Header的容器进行增删。 先定义一个测试的Controller这个Controller很简略,把客户端的所有Header,以JSON形似响应给客户端。 import java.util.ArrayList;import java.util.Enumeration;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/demo")public class DemoController { // 遍历所有申请Header,响应给客户端。 map<string, string[]> @GetMapping public Object demo (HttpServletRequest request) { Map<String, List<String>> headers = new LinkedHashMap<>(); Enumeration<String> nameEnumeration = request.getHeaderNames(); while (nameEnumeration.hasMoreElements()) { String name = nameEnumeration.nextElement(); List<String> values = headers.get(name); if (values == null) { values = new ArrayList<>(); headers.put(name, values); } Enumeration<String> valueEnumeration = request.getHeaders(name); while (valueEnumeration.hasMoreElements()) { values.add(valueEnumeration.nextElement()); } } return headers; }}应用Tomcat作为容器Tomcat对HttpServletRequest的实现Tomcat应用了外观模式(Facade),这个实现略微有一点点简单 ...

May 10, 2021 · 2 min · jiezi

关于servlet:SpringBoot工程中Web-mvc-请求参数的处理servlet

背景剖析传统java web利用,例如在servlet中获取申请数据,咱们可能间接HttpServletRequest对象获取申请中的url,参数等相干信息(request.getParameter("...")).当然咱们获取到这些参数当前,咱们可能还要进行参数的解析,类型的转换等等. 思考:第一:如果咱们在一个传统的servlet利用中,向服务端发送了一个这样的申请,例如http://localhost/findObjects?pageCurrent=1此时服务端要获取申请中的pageCurrent的值,并赋值给你整数变量你会怎么做? `String page=request.getParameter("pageCurrent");if(page!=null&&"".equals(page)){ Integer pageCurrent=Integer.parseInt(page);}`第二:如果咱们在一个传统的servlet利用中,向服务端发送了一个这样的申请,例如http://localhost/deleteObjects?ids=1,2,3,4,5此时服务端要获取申请中的ids值,而后将这个ids字符串中多个id值存储一个整数数组,你会怎么做? String idsStr=request.getParameter("ids");String []idArray=idsStr.split(",");Integer []ids=new Integer[idArray.length];for(int i=0;i<idArray.length;i++){ ids[i]=Integer.parseInt(idArray[i]);}第三:如果咱们在一个传统的servlet利用中,向服务端发送了一个这样的申请,例如http://localhost/saveObject?id=10&name=20&remark=30此时服务端获取了申请数据当前,要将申请数据存储到Goods对象中,你会怎么做呢? String id=request.getParameter("id");String name=request.getParameter("name");String remark=request.getParameter("remark");Goods g=new Goods();g.setId(Integer.parseInt(id));g.setName(name);g.setRemark(remark)对于如上几种申请参数获取,解析,封装.这样的过程,在咱们的程序中可能会重复呈现,可能对如上重复执行的逻辑或模板性的代码进行简化,进而进步开发效率? 1)间接量形式(八种根本数据类型或者封装类,字符串类型,日期类型,数组)2)pojo对象形式(要求pojo对象中提供与申请参数匹配的set办法)3)map对象形式(须要应用指定注解办法中map类型参数进行形容)4)Rest格调的url中的参数. 1)Spring MVC 管制层办法中的参数值都来自于哪个对象?request2)Spring MVC 管制层办法参数中罕用注解你晓得有几个呢?2.1)@RequestParam (定义参数规定,例如参数是否可选,指定获取哪个参数的值)2.2)@DateTimeFormat (定义能够获取的日期的日期格局)2.3)@RequestBody(示意参数能够接管客户端post申请提交的json原生数据)2.4)@PathVariable(示意参数的值来自url中{}表达式中的数据)3)Spring MVC管制办法上定义申请形式,申请url的注解你理解的有哪些?3.1)@RequestMapping(value="/doGet",method=RequestMethod.GET)3.2)@GetMapping("/path") 个别利用于查问数据的申请形式定义3.3)@PostMapping("/path") 个别利用于增加数据的申请形式定义3.4)@DeleteMapping("/path") 个别利用于删除数据的申请形式定义3.5)@PutMapping("/path") 个别利用于更新数据的申请形式定义 BUG? 1)400 (客户端向服务端传递的申请参数与服务端可解决的模式不匹配)2)405 (客户端申请形式与服务端定义的申请解决形式不匹配)3)404 (客户端申请的资源不存在)

March 13, 2021 · 1 min · jiezi

关于servlet:过滤器和监听器

过滤器和监听器次要内容过滤器介绍 Filter 即为过滤,用于在 Servlet 之外对 Request 或者 Response 进行批改。它次要用于对用户申请进行预处理,也能够对 HttpServletResponse 进行后处理。应用 Filter 的残缺流程: Filter 对用户申请进行预处理,接着将申请交给 Servlet 进行解决并生成响应,最初 Filter 再 对服务器响应进行后处理。在一个 web 利用中,能够开发编写多个 Filter,这些 Filter 组合 起来称之为一个 Filter 链。 单个过滤器 多个过滤器 若是一个过滤器链:先配置先执行(申请时的执行程序);响应时: 以相同的程序执行。 在 HttpServletRequest 达到 Servlet 之前,拦挡客户的 HttpServletRequest 。依据须要查看HttpServletRequest,也能够批改 HttpServletRequest 头和数据。 在HttpServletResponse 达到客户端之前,拦挡 HttpServletResponse。依据须要查看 HttpServletResponse,也能够批改 HttpServletResponse头和数据。 实现 能够通过实现一个叫做javax.servlet.Fileter的接口来实现一个过滤器,其中定义了 三个办法,init(), doFilter(), destroy()别离在相应的机会执行。前期察看生命周期。 Filter 的实现只须要两步: Step1: 编写 java 类实现 Filter 接口,并实现其 doFilter 办法。 ...

November 27, 2020 · 4 min · jiezi

关于servlet:Servlet

Servlet次要内容 ----IDEA的装置与应用 IDEA 全称 IntelliJ IDEA,由JetBrains公司开发,是java编程语言开发的集成环境。在业界被公认为最好的java开发工具,尤其在智能代码助手、代码主动提醒、重构、J2EE反对、各类版本工具(git、svn等)、JUnit、CVS整合、代码剖析、 翻新的GUI设计等方面的性能能够说是超常的。 IDEA的特色性能智能选取丰盛的导航模式历史记录性能编码辅助灵便的排版性能代码查看完满的主动代码实现版本控制的反对… IDEA的下载在浏览器中IntelliJ IDEA百度一下,关上如下官网进入官网,单击DOWNLOAD抉择指定版本,点击DOWNLOAD点击保留,进行下载下载之后的文件IDEA的装置双击运行安装程序,点击 “Next” 下一步批改装置门路(也可应用默认门路),点击 "Next”依据本人电脑的操作系统,来进行相应的抉择默认即可,间接抉择 “Install” ,进行装置装置胜利,可抉择运行IDEA,点击 “Finish” 实现装置若之前装置过其余版本的IDEA,会提醒是否导入原来的配置(抉择不导入即可)抉择本人喜爱的主题,而后始终抉择 “Next”。抉择 "Activation code"形式,输出激活码,点击 “OK”呈现如下画面,则示意激活胜利IDEA创立我的项目创立Java我的项目点击 “Create New Project”增加新的 JDK 版本 (idea默认应用自带的版本)抉择JDK版本,而后 “Next”抉择 “Next”设置项目名称及工作空间我的项目目录构造及提示信息 (提示信息可抉择"Close")创立Java类点击 “src” —> “new” —> “package”,创立一个文件包设置包名,与Eclipse的包相似在包上面创立 Java 类文件,点击包名 —> “New” —> “Java Class”抉择类型,并设置类的名称在类中写一个main办法执行main办法形式一:代码左侧的绿色三角符号形式二:在类中右键,抉择Run或Debug形式三:点击最上方菜单栏的Run呈现以下弹框,点击要运行的文件名,这里是 Hello 运行后果IDEA的根本设置 应用IDEA时,能够对它进行一些简略的设置,通过设置用户的偏好设置,可进步使用者的体验感。 进入设置页面抉择右下角的 “Configure”,抉择"Settings" (或在IDEA中,抉择左上角的 “File”,抉择"Settings")进入设置页面设置字体在Settings窗口中,点击 “Editor” —> “Color Scheme”抉择 “Color Scheme Font”,设置字体格调和字体大小,设置完之后抉择 “Apply” 利用设置中文字体Idea更新2019.2后 中文字体的默认成果 批改字体之后的成果 解决方案: “Editor” —> “Font” —> “Fallback font”, 抉择 SimHei ...

November 25, 2020 · 9 min · jiezi

关于servlet:Servelet

1.什么是servelet:Servelet实质上是一段Java程序,和之前的Java程序不同的是,Servlet程序无奈独立运行,须要将Servlet程序放在服务器中(比方tomcat服务器),由服务器调用才能够执行。-----Servlet: 服务器端的Java程序. 2.Servelet作用:其作用是对服务器接管过去的申请进行解决(作用为解决申请) 继承HttpServlet类,默认会笼罩doGet办法和doPost办法,两个办法的作用为: doGet办法:当浏览器发送申请的形式为GET提交时, 将会调用doGet办法来处理申请 doPost办法:当浏览器发送申请的形式为POST提交时,将会调用doPost办法来解决申请提醒:如果当GET提交和POST提交解决代码雷同时,能够将代码写在其中一个方法里(例如写在doGet中),并在另外一个办法(例如doPost)中调这个办法。这样一来,不论是GET提交还是POST提交,最终doGet办法都会执行,都会对申请进行解决!! Servlet在web.xml中的配置创立servelet时,会主动配置web.xml文件(如果是复制servelet文件,配置文件不会跟着一起复制,需本人配置)(3.0以上版本创立web工程不主动增加web.xml)对于下面的配置信息:a) Eclipse每创立一个Servlet,就会在web.xml文件中增加两个标签:<servlet>和<servlet-mapping>标签(能够将这两个标签看成一个组的标签)b) <servlet>和<servlet-mapping>标签内都会有一个<servlet-name>标签,标签的内容能够更改,但要求更改后的这两个<servlet-name>标签的内容也必须统一。c) <servlet-class>标签用于配置Servlet类的全限定类名(即包名+类名)须要留神:如果在创立Servlet后批改了Servlet类的名称,这个中央也要一起更改,否则将会呈现"ClassNotFoundException" 即类找不到异样d) <url-pattern>标签用于配置浏览器以什么门路拜访以后Servlet(即Servlet对外拜访的门路),默认的门路是:/类名例如:下面为HelloServlet配置的<url-pattern>为/HelloServlet,因而咱们在浏览器中的拜访门路则为:http://主机名/web我的项目拜访门路... request和response介绍request:封装了浏览器发送给服务器的申请信息(申请行、申请头、申请实体等)申请参数:超链接前面通过问号提交的数据,都是申请参数。申请参数时的中文乱码:get:tomcat8.0当前提交不会post:request.setCharacterEncoding("utf-8");(告诉服务器在接管POST提交的参数时,应用utf-8编码来接管!) 作为域对象应用request对象上的map汇合以及request对象的所在范畴称之为域对象存数据:request.setAttribute(String attrName, Object attrValue);-- 往request域中存入一个域属性,属性名(key)只能是字符串,属性值(value)能够是任意类型。取对象:request.getAttribute(String attrName);-- 依据属性名(key)获取对应的属性值(value)。返回的是一个Object类型的对象。 申请转发(forward)(1)转发是一次申请,一次响应(2)申请转发前后,浏览器的地址栏地址不会发生变化。(浏览器--拜访--> A --转发--> B,地址栏地址始终指向A的地址)(3)申请转发前后的两个资源必须属于同一个Web利用,否则将无奈进行转发。(A--转发-->B,A和B必须属于同一个Web利用!)(4)在转发时,能够带数据到目的地(比方,从A转发到B,能够从A带数据给B,须要配合域对象才能够 response:封装服务器要发送给浏览器的响应信息(状态行、响应头、响应实体),在service办法执行完后,服务器再将response中的数据取出,依照HTTP协定的格局发送给浏览器。向客户端发送数据:PrintWriter out = response.getWriter();乱码问题:在响应数据之前,告诉服务器应用utf-8发送数据。response.setContentType( "text/html;charset=utf-8" ); 实现重定向(redirct)(1)重定向是两次申请、两次响应(2)重定向前后,浏览器的地址栏地址会发生变化。(因为两次申请都是通过浏览器发动,浏览器晓得这个跳转的过程,因而地址栏地址会变动)(3)重定向前后的request对象不是同一个(因为重定向是两次申请,服务器会依据两次申请创立两个不同的request对象,request对象不是同一个,也就不能在重定向时通过request带数据到目的地。)(4)重定向前后的两个资源能够是来自不同的web利用,甚至能够是来自不同的服务器。(进行跳转的两个资源之间没有限度)实现代码:response.sendRedirect(所重定向到资源的URL地址); 申请转发(forward)和重定向(redirect)的区别?(1)申请转发是一次申请,一次响应; 而重定向是两次申请两次响应(2)申请转发前后地址栏地址不会发生变化; 而重定向前后地址栏地址会发生变化(3)申请转发前后的request对象是同一个,能够配合request域对象带数据到目的地;而重定向前后的request对象不是同一个, 不能联合request域对象在重定向前后带数据.(4)申请转发要求两个资源必须属于同一个Web利用; 而进行重定向的两个资源能够是同一个Web利用,也能够不是同一个Web利用,甚至能够是来自于不同的主机或服务器. 什么时候用申请转发(forward)?什么时候用重定向(redirect)?(1)如果心愿跳转前后地址栏地址不会发生变化, 只能应用转发; 如果心愿跳转前后地址栏地址会发生变化, 只能应用重定向(2)如果心愿在跳转前后, 可能通过request对象带数据到目的地, 只能应用转发(3)如果仅仅是做一个跳转,没有其余要求,此时举荐应用转发(转发是一次申请,一次响应,能够缩小拜访服务器的次数,升高服务器的压力)

November 7, 2020 · 1 min · jiezi

关于servlet:Servlet入门

1.什么是Servlet?Servlet是由SUN公司提供的一门动静Web资源开发技术 动态web资源:不同的人,在不同的条件下拜访后看到的是雷同的成果,这样的资源叫做动态web资源(html,css,js等) 动静web资源:在不同的拜访条件下看到的是不同的成果,这样的资源叫做动静web资源。(Servlet,jsp,.net,php等) Servlet实质上是一段Java代码,和之前的Java程序不同的是,Servlet程序无奈独立运行,须要讲Servelt程序放在服务器中,(比方tomcat服务器),由服务器调用才能够执行。 Servlet:服务器端的Java程序. Servlet是运行在服务器端的Java程序,其作用是什么? 其作用是对服务器接管过去的申请进行解决(作用为解决申请) 2.开发Servlet程序第一步:写一个类,实现一个Servlet接口或者继承Servlet接口的子类(GenericServlet/HttpServlet),并实现其中的办法 Servlet接口 GenericServlet类(抽象类) HttpServlet类第二步:在Web利用的web.xml文件中配置Servlet程序对外拜访门路。Eclipse在创立一个Servelt时,会在web.xml文件中生成Servlet配置,所以不须要咱们手动配置。 应用Eclipse创立Web我的项目 以上是Web我的项目在工程视图(Project)和包视图(package)下构造,举荐应用包视图! 1.创立一个Web工程:在左侧窗口中,点击鼠标右键---->New--->Dynamic Web Project. 2.接着会弹出如下窗口: 留神: (1) 3.0版本不会创立web.xml文件,并且创立Servlet时也不会在web.xml文件中生成Servelt相干的配置信息,记得改为2.5. (2) Target runtime选项中如果没有可选的服务器,可点击右侧的New Runtime...进行配置。 详情操作步骤在《5.2配置Target runtime(Web我的项目运行环境)》 3.Eclipse中创立的Web工程的目录构造 (1) day09 : 工程名称/项目名称 (2) src : 源码目录,创立的java源文件,配置文件(properties,xml文件等)都能够放在src源码目录下 (3) build/classes: 编译文件的输入目录,src源码目录中的文件编译后会输入到classes目录下。 其中的classes目录会在公布时会放在WEB-INF目录下,随着我的项目一起公布到服务器中(4) WebContent :就是Web利用的目录,其中能够寄存 html,css,js,jsp,图片以及编译后的class文件,jar包,web.xml文件等。未来公布我的项目到服务器,其中就是将WebContent中的所有内容一起公布到服务器中。 (5) WebContent/WEB-INF/lib: 用于寄存以后我的项目所依赖的jar包。比方要拜访mysql数据库,须要导入mysql驱动包,间接将jar包拷贝到lib目录下即可!(也不必再去做 build path --> add to build path) 应用Eclipse创立Servlet 1.选中我的项目中的src目录,鼠标右键--->New--->Servlet 2.在弹出的窗口中,依据提醒填写内容 3.点击Finish即可实现Servlet创立过程,创立好的Servlet如下: 通过Eclipse创立Servlet,默认继承HttpServlet。因为HttpServlet也是Servlet接口的子类,让HelloServlet继承HttpServlet,相当于间接实现了Servelt接口 ...

September 30, 2020 · 1 min · jiezi

关于servlet:JavaWebServlet概述及快速入门

Servlet概述servlet = server + applet: 运行在服务器端的java程序Servlet是一个接口. 一个类要想通过浏览器被拜访到, 那么这个类就必须间接或间接的实现Servlet接口作用: 接管申请, 解决逻辑, 响应后果疾速入门案例案例需要编写一个一般的java类,通过浏览器能够拜访代码编写步骤剖析创立Web我的项目编写一般Java类, 实现Servlet接口在web.xml中配置url-pattern部署web我的项目启动测试步骤实现创立Web我的项目 编写一般Java类,实现Servlet接口执行原理

September 16, 2020 · 1 min · jiezi

关于servlet:Servlet和Tomcat

一.Tomcat: web服务软件,中小型的JavaEE服务器,仅仅反对大量的JavaEE标准servlet/jsp。批改端口号:在conf/server.xml,也能够在idea中批改部署web我的项目的办法有三种 间接将我的项目放到webapps目录下即可。配置conf/server.xml文件在confCatalinalocalhost创立任意名称的xml文件。在文件中编写<Context docBase="D:hello" />* 虚拟目录:xml文件的名称部署我的项目到idea中,new project,java ee。而后去配置tomcat的配置文件 二.Servlet: 实现: 定义一个类,实现Servlet接口:public class ServletDemo1 implements Servlet实现接口办法去web.xml去配置Servlet<!--配置Servlet --> <servlet> <servlet-name>demo1</servlet-name> <servlet-class>cn.itcast.web.servlet.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>demo1</servlet-name> <url-pattern>/demo1</url-pattern> </servlet-mapping> 执行原理: 当服务器承受到客户端浏览器的申请后,会解析申请URL门路,获取拜访的Servlet的资源门路查找web.xml文件,是否有对应的<url-pattern>标签体内容。如果有,则在找到对应的<servlet-class>全类名tomcat会将字节码文件加载进内存,并且创立其对象调用其办法也能够用Servlet3,在创立我的项目时能够抉择,用Servlet3就比较简单,不必去配置web.xml文件,只须要注解配置,其中/demo就是urlPatterns(),和在web.xml配置的原理一样。 @WebServlet("/demo")public class ser implements Servlet{ @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("init"); }Servlet中的生命周期办法: 被创立:执行init办法,只执行一次 默认状况下,第一次被拜访时,Servlet被创立能够配置执行Servlet的创立机会。在<servlet>标签下配置 1. 第一次被拜访时,创立: `<load-on-startup>`的值为正数在服务器启动时,创立: <load-on-startup>的值为0或正整数Servlet的init办法,只执行一次,阐明一个Servlet在内存中只存在一个对象,Servlet是单例的。 多个用户同时拜访时,可能存在线程平安问题。解决:尽量不要在Servlet中定义成员变量。即便定义了成员变量,也不要对批改值。比方买票,定义个成员变量,他就会共享。如果同时买票,或者退票,就会呈现问题。提供服务:执行service办法,执行屡次:每次拜访Servlet时,Service办法都会被调用一次。被销毁:执行destroy办法,只执行一次。 Servlet被销毁时执行。服务器敞开时,Servlet被销毁,只有服务器失常敞开时,才会执行destroy办法。destroy办法在Servlet被销毁之前执行,个别用于开释资源。

August 27, 2020 · 1 min · jiezi

关于servlet:Eclipse中创建的Web工程的目录结构

(1) day09: 工程名称/项目名称(2) src: 源码目录, 创立的java源文件、配置文件(properties、xml文件等)都能够放在src源码目录下(3) build/classes: 编译文件的输入目录, src源码目录中的文件编译后会输入到classes目录下。其中的classes目录在公布时会放在WEB-INF目录下,随着我的项目一起公布到服务器中(4) WebContent: 就是Web利用的目录,其中能够寄存 html、css、js、jsp、图片以及编译后的class文件、jar包、web.xml文件等. 未来公布我的项目到服务器,其实就是将WebContent中的所有内容一起公布到服务器中。(5) WebContent/WEB-INF/lib: 用于寄存以后我的项目所依赖的jar包。比方要拜访mysql数据库,须要导入mysql驱动包,间接将jar包拷贝到lib目录下即可!(也不必再去做 build path --> add to build path)

August 27, 2020 · 1 min · jiezi

关于servlet:添加Servlet模板

1.通过Eclipse创立一个Servlet类,将其中的内容批改成本人冀望的模板格局,并复制其内容,例: package ${enclosing_package};import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * author: bjzhangsz@tedu.cn * datetime: ${date} ${time} */public class ${primary_type_name} extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {![image](/img/bVbLWib) doGet(request, response); }}2.点击菜单栏中的windows-->3.在呈现的窗口左侧顺次点击:Java-->Editor-->templates-->(在左边的窗口中) 点击New… :4.呈现的新窗口填写:5.替换包门路和类名(作用是在新建Servlet生成的Servlet模版中应用以后类的包门路和类型)图: 成果:6.点击OK保留,创立新的Servlet文件,测试: 将原有的Servlet所有内容删除,并输出"servlet",按"Alt+/"生成

August 26, 2020 · 1 min · jiezi

关于servlet:Servlet的管理机制生命周期和继承关系

Servlet的管理机制浏览器每一次拜访服务器都会发送一个信息的申请,每一次发送申请如果是申请操作,那么调用的Servlet对象是惟一的。为了保障Servlet对象是惟一的,就须要让服务器去治理Servlet对象,保障它的唯一性。治理形式次要有如下两种:(采纳Tomcat服务器) - 立刻加载:当服务器启动时,底层就会依据web.xml配置文件找到所有Servlet类,并通过反射机制创建对象将对象保留在汇合中,当须要调用Servlet对象,就从该汇合中取出来- 提早加载:当服务器启动时,不会事后创立所有的Servlet对象,而是什么时候用到就什么时候创立Tomcat服务器采纳的是提早加载的形式(这是默认的形式)当Tomcat启动的时候,Tomcat读取了web.xml配置文件,首先读取申请的操作名和对应的名字,也就是配置文件中的url-parttern和servlet-name,将这两个名字存入一个键值对的汇合中保存起来。并且还有另一个键值对汇合是用来存储和servlet-name对应的servlet-class,然而这个不是一开始就加载,而是当须要用Servlet对象的时候再创立,并将创立之后的对象保留到该汇合中。咱们能够扭转默认加载的形式,只有在web.xml配置文件中,在<servlet>下增加一个配置,<load-on-startup>整数0</load-on-startup><servlet> <servlet-name>test</servlet-name> <servlet-class>TestController</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>test</servlet-name> <url-pattern>/test</url-pattern> </servlet-mapping>那么在Tomcat启动时,这个servlet类就会被创立 Servlet生命周期Tomcat为了更好的治理servlet对象的产生和销毁,提供了三个办法标识Servlet对象的生命周期,别离是init(),service()和destroy(); servlet通过调用init()办法进行初始化 因为servlet对象是单例的,所以init()在servlet第一次创立的时候就被调用,之后就不会再被调用servlet调用service()来解决客户端发送过去的申请每一次服务器收到一个操作申请时,服务器就会产生一个线程并调用servlet,执行service()办法servlet通过调用destroy()办法中值 当servlet生命周期完结时会调用,会调用一次destroy()办法Servlet的继承关系HttpServlt类继承了一个抽象类GenericServletGenericServlet实现了三个接口,别离是Servlet、ServletConfig和SerializableServletConfig接口有四个办法 String getServletName();ServletContext getServletContext();String getInitParameter(String var1);Enumeration<String> getInitParameterNames();Servlet接口外面有五个办法 void init(ServletConofig var1) throws ExceptionServletConfig getServletConfig();void service(ServletRequest var1, ServletResponse var2);void destroy();String getServletInfo();GenericServlet抽象类(实现了ServletConfig和Servlet接口,体现出了缺省适配器模式) 将两个接口中的9个办法都增加了过去,将其中的8个办法都进行了重写,除了Destroy()多增加了一个init()无参数的办法留下一个办法是没有具体实现的service办法增加了log()办法HttpServlet抽象类 存在的目标:增加了具体的申请形式对应的办法,比方doGet、doPostHttpServlet保留了GenericServlet抽象类的Service,本人增加了一个带两个参数HttpServletRequest和HttpServletResponse的service办法,保留的这个service最终调用了自带的service形式。本人增加的service办法内容先获取申请的形式,最初调用绝对应的办法比方doGet/doPost执行本篇文章到此就完结了,次要也是记录我的一个学习过程,请读者带着批评的角度去浏览,如有谬误还望纠正

July 17, 2020 · 1 min · jiezi

关于servlet:Servlet的介绍与使用

Servlet介绍Servlet是运行在Web服务器或应用服务器上的程序,它是作为来自Web浏览器或其余HTTP客户端的申请和HTTP服务器上的数据库或应用程序之间的中间层,上面所说的web服务器以Tomcat为例 MVC架构介绍理解申请和响应的过程能更好的了解Servlet做的事件。这里咱们联合MVC架构进行形容,先介绍什么是MVC V是View的简写,为视图层,就是用户可能看到的局部,比方浏览器的页面C是Controller的简写,为管制层,解决浏览器发送过去的申请,将申请交由模型层去解决,并将解决的最初后果返回给浏览器,中间层的含意。M是Model的简写,为模型层,模型层又能够细分三个局部 service:解决业务逻辑,比如说浏览器发送一个用户登录的申请,服务器接管到之后把它交由管制层去解决,管制层接管到之后交给service,让service去解决用户登录的后果,判断用户的账号和明码是否正确dao:数据长久层,用来读取和写入数据,联合下面提到的登录用例,当service要判断用户的账号和明码是否正确时,service首先要从数据库中查找该账号和对应的明码。这时候service把查找这件事交由给dao去负责,dao连贯数据库查找,将查找获取到的后果包装成domain实体返回给service,service再依据返回的后果进行判断domain:用来示意实体局部,也就是Java中的类,一个用户对象就是一个实体申请和响应的过程联合我所画的图阐明整个过程假如浏览器发给服务器一个登录的申请,整个过程如下: 浏览器向服务器发送一个登录申请,服务器接管到申请之后,调用handler线程解决申请,handler先解析申请,获取申请的资源名和申请携带的参数,之后将申请的资源名和申请携带的参数包装成request对象,并创立response对象,response对象用来寄存响应回来的信息。最初将request和response发给ServletController类ServletController类接管到之后,首先先从request对象中获取申请的资源名,判断是动态资源还是操作资源。因为登录是操作资源,所以ServletController会参考我的项目当中的配置文件,寻找有没有一个叫登录的操作,如果有的话会依据配置文件中登录操作对应的Controller类,并将申请交给这个Controller类。如果没有的话返回404状态码给浏览器,示意并没有这个操作资源这个具体的Controller类是继承自HttpServlet,HttpServlet有一个service办法,controller重写了这个办法。当ServletController将申请交给这个具体的Controller对象,这个对象会执行service办法,在service办法中调用service层的对象解决业务逻辑service执行完之后将后果返回给controller对象,这个对象将失去的后果写回给浏览器浏览器接管后将响应信息展现给用户这就是大抵的一个流程,但并不是所有的申请响应过程都是截然不同,有的可能比较复杂,有的可能比较简单 Servlet的应用在下面提到的申请和响应的过程中,Servlet就是Controller类,controller继承了Servlet类。创立一个Servlet类,须要如下几步(这里我用的是IDEA编译器,应用的Tomcat容器) 创立一个类,继承HttpServlet重写Service办法,办法里带有两个参数HttpServletRequest和HttpServletResponse,办法有两个异样ServletException和IOException,办法是没有返回值的。代码如下: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 TestController extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("这是Servlet类"); }}配置文件,该配置文件是告知Tomcat服务器有一个本人定义的类须要治理,在我的项目下的web文件夹下的WEB-INFO文件夹中的web.xml文件,配置信息如下: <servlet> <servlet-name>test</servlet-name> <servlet-class>TestController</servlet-class> </servlet> <servlet-mapping> <servlet-name>test</servlet-name> <url-pattern>/test</url-pattern> </servlet-mapping>url-pattern是申请的操作名,servlet-name是申请操作名对应的名字,servlet-class是servlet-name对应的Servlet类。 运行启动Tomcat服务器,关上浏览器输出URL地址+申请的操作名,如下:http://localhost:8080/untitled_war_exploded/test在控制台就能看到TestController执行了,输入信息如下: 本篇文章就到此结束,下篇文章将介绍Servlet对象的继承关系

July 17, 2020 · 1 min · jiezi

深入理解Servlet

1、什么是 Servlet ?Servlet(Server Applet)是 Java Servlet 的简称,称为小服务程序或服务连接器,用 Java 编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态 Web 内容。 狭义的 Servlet 是指 Java 语言实现的一个接口,广义的 Servlet 是指任何实现了这个 Servlet 接口的类,一般情况下,可以将 Servlet 理解为后者。Servlet 运行于支持 Java 的应用服务器中。 从原理上讲,Servlet 可以响应任何类型的请求,但绝大多数情况下 Servlet 只用来扩展基于 HTTP 协议的 Web 服务器。(内容摘自百度百科) * 概念:运行在服务器端的小程序 * Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。 * 将来我们自定义一个类,实现Servlet接口,复写方法。创建项目进行代码演示:/** * Created by RookieLi on 2019/4/22. */public class ServletDemo implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException {} @Override public ServletConfig getServletConfig() { return null; } // 提供服务的方法 @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("hello,servlet"); } @Override public String getServletInfo() { return null; } @Override public void destroy() {}}在 web.xml 中配置:<servlet> <servlet-name>demo1</servlet-name> <servlet-class>com.rookie.web.ServletDemo</servlet-class></servlet><servlet-mapping> <servlet-name>demo1</servlet-name> <url-pattern>/demo</url-pattern></servlet-mapping>当在浏览器中输入路径:http://localhost:8080/demo控制台会输出:hello,servlet执行的原理:A、当服务器接受到客户端浏览器的请求后,会解析请求 URL 路径,获取访问的 Servlet 的资源路径。B、查找 web.xml 文件,是否有对应的 <url-pattern> 标签体内容。C、如果有,则在找到对应的 <servlet-class> 全类名D、tomcat会将字节码文件加载进内存,并且创建其对象E、调用其 service 方法Servlet中的生命周期方法:A、被创建:执行init方法,只执行一次 Servlet 何时被创建? * 默认情况下,第一次被访问时,Servlet 被创建 * 可以配置执行 Servlet 的创建时机。 * 在 <servlet> 标签下配置 a. 第一次被访问时,创建 * <load-on-startup>的值为负数 b. 在服务器启动时,创建 * <load-on-startup>的值为0或正整数 * Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的。 * 多个用户同时访问时,可能存在线程安全问题。 * 解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值。B、提供服务:执行service方法,执行多次 * 每次访问Servlet时,Service方法都会被调用一次。C、被销毁:执行destroy方法,只执行一次 * Servlet被销毁时执行。服务器关闭时,Servlet被销毁。 * 只有服务器正常关闭时,才会执行destroy方法。 * destroy方法在Servlet被销毁之前执行,一般用于释放资源。Servlet 3.0 (重点)优点:支持注解配置。可以不需要 web.xml 了。代码演示@WebServlet("/demo666")public class ServletDemo2 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException {} @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("servlet 3.0 给力 666"); } @Override public String getServletInfo() { return null; } @Override public void destroy() {}}当在浏览器中输入路径:http://localhost:8080/demo666控制台会输出:servlet 3.0 给力 666@WebServlet 源码剖析@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface WebServlet { String name() default ""; //相当于<Servlet-name> String[] value() default {}; //代表urlPatterns()属性配置 String[] urlPatterns() default {}; //相当于<url-pattern> int loadOnStartup() default -1; //相当于<load-on-startup> WebInitParam[] initParams() default {}; boolean asyncSupported() default false; String smallIcon() default ""; String largeIcon() default ""; String description() default ""; String displayName() default "";}Servlet 的体系结构 Servlet -- 接口 | GenericServlet -- 抽象类 | HttpServlet -- 抽象类 A、GenericServlet:将 Servlet 接口中其他的方法做了默认空实现,只将 service() 方法作为抽象 * 将来定义 Servlet 类时,可以继承 GenericServlet ,实现 service() 方法即可B、HttpServlet:对 http 协议的一种封装,简化操作 * 定义类继承 HttpServlet * 复写 doGet/doPost 方法 C、Servlet相关配置 * urlpartten:Servlet访问路径 * 一个Servlet可以定义多个访问路径:@WebServlet({"/demo6","/demo66","/demo666"}) 在浏览器中输入不同的请求路径,都可以访问到资源。 http://localhost:8080/demo6 http://localhost:8080/demo66 http://localhost:8080/demo666 B、路径定义规则: 1. /xxx:路径匹配 2. /xxx/xxx:多层路径,目录结构 3. *.do:扩展名匹配

November 4, 2019 · 2 min · jiezi

Servlet-异常处理

免费Java入门课程:阿里云大学——开发者课堂当一个 Servlet 抛出一个异常时,Web 容器在使用了 exception-type 元素的 web.xml 中搜索与抛出异常类型相匹配的配置。必须在 web.xml 中使用 error-page 元素来指定对特定异常 或 HTTP 状态码 作出相应的 Servlet 调用。 web.xml 配置假设,有一个 ErrorHandler 的 Servelt 在任何已定义的异常或错误出现时被调用。以下将是在 web.xml 中创建的项。 <!-- servlet 定义 --><servlet> <servlet-name>ErrorHandler</servlet-name> <servlet-class>ErrorHandler</servlet-class></servlet><!-- servlet 映射 --><servlet-mapping> <servlet-name>ErrorHandler</servlet-name> <url-pattern>/ErrorHandler</url-pattern></servlet-mapping><!-- error-code 相关的错误页面 --><error-page> <error-code>404</error-code> <location>/ErrorHandler</location></error-page><error-page> <error-code>403</error-code> <location>/ErrorHandler</location></error-page><!-- exception-type 相关的错误页面 --><error-page> <exception-type> javax.servlet.ServletException </exception-type > <location>/ErrorHandler</location></error-page><error-page> <exception-type>java.io.IOException</exception-type > <location>/ErrorHandler</location></error-page>如果您想对所有的异常有一个通用的错误处理程序,那么应该定义下面的 error-page,而不是为每个异常定义单独的 error-page 元素: <error-page> <exception-type>java.lang.Throwable</exception-type > <location>/ErrorHandler</location></error-page>以下是关于上面的 web.xml 异常处理要注意的点:1 Servelt ErrorHandler 与其他的 Servelt 的定义方式一样,且在 web.xml 中进行配置。2 如果有错误状态代码出现,不管为 404(Not Found 未找到)或 403(Forbidden 禁止),则会调用 ErrorHandler 的 Servlet。3 如果 Web 应用程序抛出 ServletException 或 IOException,那么 Web 容器会调用 ErrorHandler 的 Servlet。4 您可以定义不同的错误处理程序来处理不同类型的错误或异常。上面的实例是非常通用的,希望您能通过实例理解基本的概念。 ...

June 6, 2019 · 1 min · jiezi

Java基础Servlet

什么是ServletServlet是Java Web的三大组件之一,它属于动态资源。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要: 接收请求数据; 处理请求; 完成响应。例如客户端发出登录请求,或者输出注册请求,这些请求都应该由Servlet来完成处理!Servlet需要我们自己来编写,每个Servlet必须实现javax.servlet.Servlet接口。 实现Servlet的方式有三种: 实现javax.servlet.Servlet接口; 继承java.servlet.GenericServlet类; 继承javax.servlet.http.HttpServlet类;通常我们会去继承HttpServlet类来完成我们的Servlet,但学习Servlet还要从javax.servlet.Servlet接口开始学习。 阿里云大学全新“学+测”模式,提供Java基础测试题(当前已有58522人参加), 评估你的Java基础水平,参加测试后学习提升效果更精准!马上开始测试:https://edu.aliyun.com/cloude...Servlet免费学习视频:https://edu.aliyun.com/course...

May 27, 2019 · 1 min · jiezi

javaweb开发之servlet初始

servlet概述Servlet是sun公司提供的一门用于开发动态web资源的技术。Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤: (1)编写一个Java类,实现servlet接口。(2)把开发好的Java类部署到web服务器中。(3)按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servletservlet运行过程: (1)Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后: ①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。 ②装载并创建该Servlet的一个实例对象。 ③调用Servlet实例对象的init()方法。 ④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。 ⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。 IDEA创建第一个servlet程序选中自己的project,打开Project Structure界面》》选中Libraries》》点击"+"并选择java》》选择并选中自己的tomcat/lib/servlet-api.jar》》Apply》》OK列表项目

April 28, 2019 · 1 min · jiezi

1713-非阻塞-IO

应用程序的web容器通常为每一个客户端请求分配一个服务端线程。开发可扩展的web应用,你必须确保关联请求的线程是没有空闲的,不需要等待一个阻塞操作完成。异步处理提供了在一个新线程处理阻塞操作的机制,把关联请求的线程返回给容器。即使你所有的阻塞操作都在service方法中异步执行,关联客户端请求的线程基于input/output也可能出于暂时空闲状态。 例如,如果一个客户端在一个很慢的网络连接上提交一个大的HTTP POST请求,server读取请求的速度比客户端上传的速度快很多。使用TIO,容器关联请求的线程有时会出于空闲状态,因为要等待客户端的请求的其余部分。 JAVA EE异步模式处理请求时,提供支持servlet和filter的NIO。下面的步骤总结了在service方法中如何使用NIO处理请求和写出响应: 1. 如 Asynchronous Processing章节描述,把请求设置为异步模式 2. 在service方法中从请求和响应对象中获得一个请求流或一个响应流3. 分配给请求流一个监听器或者分配给响应流一个监听器 4. 在监听器的回调方法中处理请求和响应NIO 支持类 javax.servlet.ServletInputStream方法签名:void setReadListener(ReadListener rl)描述:将输入流与包含回调方法的监听器对象关联,以异步读取数据。提供的监听器对象可以是一个匿名类或者使用其他的机制给监听器对象传入输入流。 方法签名:boolean isReady() 方法描述:如果数据可以无阻塞读取,返回true方法签名:boolean isFinished() 方法描述:当所有数据读取完毕后,返回true NIO 支持类 javax.servlet.ServletOutputStream方法签名:void setWriteListener(WriteListener wl) 方法描述:将此输出流与包含回调方法的侦听器对象关联,以异步写入数据。您将写入侦听器对象提供为匿名类,或使用其他机制将输出流传递给写入侦听器对象。 方法签名:boolean isReady() 方法描述:如果数据可以无阻塞写入,返回true NIO监听器支持接口接口名称:ReadListener 接口方法:void onDataAvailable()、void onAllDataRead()、void onError(Throwable t) 描述:ServletInputStream当数据可以有效读取、当数据读取完毕、当发生一个错误时调用监听器的这些方法。 接口名称:WriteListener 接口方法:void onWritePossible()、void onError(Throwable t) 描述:ServletOutputStream当数据可以无阻塞读取、当发生一个错误时调用监听器的这些方法。 使用NIO读取大的HTTP POST请求本节代码展示了在servlet对象中怎么读取一个大的HTTP POST数据,通过把请求放入异步模式中并使用NIO功能。 @WebServlet(urlPatterns={"/asyncioservlet"}, asyncSupported=true)public class AsyncIOServlet extends HttpServlet { @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { final AsyncContext acontext = request.startAsync(); final ServletInputStream input = request.getInputStream(); input.setReadListener(new ReadListener() { byte buffer[] = new byte[4*1024]; StringBuilder sbuilder = new StringBuilder(); @Override public void onDataAvailable() { try { do { int length = input.read(buffer); sbuilder.append(new String(buffer, 0, length)); } while(input.isReady()); } catch (IOException ex) { ... } } @Override public void onAllDataRead() { try { acontext.getResponse().getWriter() .write("...the response..."); } catch (IOException ex) { ... } acontext.complete(); } @Override public void onError(Throwable t) { ... } }); }}此示例使用@WebServlet批注参数asyncSupported = true声明具有异步支持的Web Servlet。服务方法首先通过调用请求对象的startAsync()方法将请求置于异步模式,这是使用非阻塞I / O所必需的。然后,服务方法获得与请求相关联的输入流,并分配定义为内部类的读取侦听器。侦听器在可用时读取部分请求,然后在完成读取请求时将一些响应写入客户端。 ...

April 27, 2019 · 1 min · jiezi

17.12 异步处理

应用服务器的web容器通常会为每个请求分配一个服务线程。在重负载的场景下,容器需要大量的线程去服务所有客户端请求。服务可扩展性的限制包括内存不足或者耗尽容器线程。创建可扩展web程序,你必须确保没有关联请求的线程是空闲的,所以容器可以使用他们处理新请求。 这里有两个关联请求的线程空闲的两个场景: 线程需要在构建响应之前等待一个资源可用或者处理数据。例如,一个应用程序需要在构建响应前查询数据库或者通过远程web服务访问数据。线程需要在构建响应之前等待一个事件。例如,线程在构建响应之前需要等待一个JMS消息,另一个客户端的新信息,或者队列里面的新数据可用。这些场景代表限制web程序可扩展性的阻塞操作。异步处理是指给这些阻塞操作分配一个新线程,并把关联请求处理的线程返回给web容器。 servlet 异步处理java ee支持servlet和filter的异步处理。如果一个servlet或一个filter处理请求时可能到达一个阻塞操作,它可以把操作分配给一个异步处理上下文并且在不生成响应的情况下将关联请求处理的线程回送给web容器。阻塞操作在不同线程的异步上下文中执行完成,它可以生成响应或者转发请求到另一个servlet。 在一个servlet上启用异步处理,设置@WebServlet注解的asyncSupported参数为true,如下: @WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)public class AsyncServlet extends HttpServlet { ... }javax.servlet.AsyncContext类提供在Service方法中执行异步处理所需的功能。获得一个AsyncContext实例,在service方法中调用request对象的startAsync()方法;例如: public void doGet(HttpServletRequest req, HttpServletResponse resp) { ... AsyncContext acontext = req.startAsync(); ...}这个调用将请求进入异步模式并且确保响应在退出service方法时每月被提交。你必须在异步上下文完成阻塞操作时生成响应或者转发到其他servlet中。 AsyncContext类提供的基础功能描述: 方法签名:void start(Runnable run) 描述:容器提供的能提供阻塞操作处理的不同线程 方法签名:ServletRequest getRequest() 描述:返回用来初始化异步上下文的请求。在上面的例子中,request与service方法中的相同。你可以通过这个方法在异步上下文中从请求中获取参数。 方法签名:ServletResponse getResponse() 描述:返回初始化异步上下文的响应。在上面的例子中,response与service方法中的相同。你可以在异步上下文中,使用这个方法写入阻塞操作的结果到响应中。 方法签名:void complete() 描述:完成异步操作,并关闭与此异步上下文关联的响应。你可以在异步上下文完成写入响应后调用这个操作。 方法签名:void dispatch(String path) 描述:转发请求和响应到给定的路径。在阻塞操作完成后,使用这个方法调用另一个servlet写出响应。 等待一个资源这个章节示范了怎么使用AsyncContext上下文提供的功能,有如下用例: servlet从一个GET请求中获取参数servlet使用一个资源,比如一个数据库或者一个web service,基于这个参数获取信息。这个资源可能比较缓慢,所以这可能是一个阻塞操作。servlet使用资源的结果生成响应。下面的例子是一个不使用异步处理的常见servlet: @WebServlet(urlPatterns={"/syncservlet"})public class SyncServlet extends HttpServlet { private MyRemoteResource resource; @Override public void init(ServletConfig config) { resource = MyRemoteResource.create("config1=x,config2=y"); } @Override public void doGet(HttpServletRequest request, HttpServletResponse response) { response.setContentType("text/html;charset=UTF-8"); String param = request.getParameter("param"); String result = resource.process(param); /* ... print to the response ... */ }}下面的示例是同一个servlet,但使用了异步处理: ...

April 23, 2019 · 1 min · jiezi

使用Servlet技术上传文件

支持文件上传是web程序最基本和常见的需求。在早期的servlet规范中,实现文件上传需要使用第三方库或者复杂的输入处理。针对此问题,servlet现在以通用和可移植的方式帮助提供了一个可行的解决方案。servlet技术现在提供开箱即用的上传文件方法,所以任何实现规范的web容器都能通过HttpServletRequest 对象解析multipart请求和生成有效的mime附件。 一个新的注解,javax.servlet.annotation.MultipartConfig,用来表明需要multipart/form-data类型请求的定义上。使用@MultipartConfig注解的servlet都可以通过调用 request.getPart(String name)或request.getParts()方法获取一个给定的multipart/form-data请求中的Part构件。 @MultipartConfig注解@MultipartConfig注解提供下面这些可选的属性: location 操作系统上的一个绝对路径。location属性不支持基于web上下文的相对路径。location用来在处理Part时存储临时文件或者是文件大小超过fileSizeThreshold设置的值。默认location是“”fileSizeThreshold 存储在硬盘上的临时文件的大小。默认是0byteMaxFileSize 允许上传的最大文件大小,单位是byte。如果上传的文件超过限制,web容器将抛出异常(IllegalStateException)。默认设置是不限制大小。maxRequestSize 一个 multipart/form-data请求能携带的最大字节数。例如,@MultiPartConfig可以如下构造: @MultipartConfig(location="/tmp", fileSizeThreshold=1024*1024, maxFileSize=1024*1024*5, maxRequestSize=1024*1024*5*5)代替使用 @MultipartConfig注解在你的upload servlet中硬编码这些属性,需要在web.xml中作为一个子节点添加下面的节点: <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>getParts和getPart方法servlet规范定义了HttpServletRequest的两个附加方法: Collection<Part> getParts()Part getPart(String name)request.getParts()方法返回所有Prat集合。如果你有超过一个文件类型的输入,将返回多个Part对象。因为所有Part对象都被命名, getPart(String name)方法用来访问特定的Part对象。另外,getParts()返回Iterable<Part>可以用来遍历所有Part。 javax.servlet.http.Part是简单的,提供每个Part的自省方法。方法列表: 获取Part的名称、大小、类型等查询随Part提交的Header信息删除一个Part输出Part到磁盘例如,Part 接口提供write(String filename) 方法以特定名称写入到文件中。文件可以使用@MultipartConfig注解定义的location直接保存,在fileupload示例中,location是由表达中的属性定义的。

April 21, 2019 · 1 min · jiezi

销毁servlet

web容器可能决定一个Servlet是否从servic中移除(例如,当一个容器想要回收内存资源时或者被关闭时)。在上面的场景中,容器会调用Servlet接口的destroy方法。在方法中,可以释放servlet使用的任何资源,保存持久化状态。destroy方法关闭在init方法中创建的数据库对象。 当servlet被移除时,它的service方法必须全部执行完成。服务器在所有请求被响应或者在一个特定时间后,通过调用destroy方法确保这一点的实现。当你的servlet正在执行超过服务器超时时间的长任务时,这些操作直到destroy方法被调用前都在执行。你必须确保任何持有客户端请求的线程完成。 本节的其余部分将介绍如何执行以下操作: 保持跟踪当前有多少线程在运行service方法通过destroy方法通知长时间运行的线程关闭并等待完成来提供一个干净的关闭方法让长时间运行的方法定期轮询以检查关闭,并在必要时停止工作,清理和返回跟踪服务请求要跟踪服务请求,需要在servlet类中包含一个变量,这个变量用来统计运行的service方法数量。这个变量需要使用同步方法增量、减量和返回变量值。 public class ShutdownExample extends HttpServlet { private int serviceCounter = 0; ... // Access methods for serviceCounter protected synchronized void enteringServiceMethod() { serviceCounter++; } protected synchronized void leavingServiceMethod() { serviceCounter--; } protected synchronized int numServices() { return serviceCounter; }}当每次进入service方法时都需要增长变量值,每次离开service方法时都需要减小变量值。这是你要在HttpServlet子类覆写父类service方法的原因之一。新方法需要调用super.service()保留原始的service方法的内容。 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { enteringServiceMethod(); try { super.service(req, resp); } finally { leavingServiceMethod(); }}通知方法关闭为了确保一个干净的关闭,在所有请求完成前你的service方法不能释放任何共享资源。做到这一点的一部分是检查service的数量。另外一部分是通知长时间运行的任务是时候关闭了。为了能通知到位,需要另一个变量。这个变量需要有通常的访问方法。 public class ShutdownExample extends HttpServlet { private boolean shuttingDown; ... //Access methods for shuttingDown protected synchronized void setShuttingDown(boolean flag) { shuttingDown = flag; } protected synchronized boolean isShuttingDown() { return shuttingDown; }}下面是一个使用这些变量提供干净的关闭方法的示例: ...

April 21, 2019 · 1 min · jiezi

维持客户端状态

许多应用都需要一个客户端的多个请求是相互关联。例如,一个web程序能在多个请求间保存用户的状态。基于web的应用程序都有维护这些状态的能力,因为HTTP是无状态的。为了支持这些,web应用程序需要维护状态,servlet技术提供了管理session的api,并且有几种实现会话的机制。访问一个sessionsession代表一个HttpSession对象。你可以通过请求的getSession方法访问session。这个方法返回关联到当前请求的session对象,或者,如果当前请求还没有session,这个方法会生成一个。session关联的对象你可以通过名称关联对象-值属性到session。这些属性可以被同一个web上下文处理同一个session的请求访问。 注意,你的应用程序可以通知web上下文和servlet生命周期(Handling Servlet Lifecycle Events)中的session监听器。 您还可以通知与会话关联的某些事件的对象,例如以下内容:当往session中添加或移除一个对象。为了接收通知,你的对象必须实现javax.servlet.http.HttpSessionBindingListener接口。当附加对象的session被休眠或激活。在虚拟机之间移动或保存到永久存储并从中恢复时,会话将被钝化或激活。为了接收通知,你的对象必须实现javax.servlet.http.HttpSessionActivationListener 接口。session管理因为HTTP客户端没有方法去标记是否不再需要一个session。每一个session都关联了一个超时时间,以便于资源的回收利用。这个超时阶段可以通过session的getMaxInactiveInterval 和setMaxInactiveInterval方法访问。为了确保活跃的session不被设置为超时, 您应该使用服务方法定期访问会话,因为这会重置会话的生存时间计数器。当与一个特定客户端交互完成后,你可以在服务端使用invalidate方法设置一个session无效、删除任何session数据。使用netbeans 设置超时时间要使用NetBeans集成开发环境在部署描述符中设置超时时间,请按照下列步骤操作。打开项目如果你还未打开展开你的项目Projects节点展开项目节点下的Web Pages and WEB-INF节点双击web.xml在编辑器顶端点击General按钮在Session Timeout属性中,键入数字整数值表示在会话超时之前必须经过的不活动分钟数。session跟踪要将session与用户关联,web容器有几种方法,它们都需要在客户端与服务器直接传一个唯一标识。这个唯一标识在客户端作为一个cookie维护,或者web组件在返回客户端的每一个响应中包含这个唯一标识。 如果你的应用使用了session对象, 您必须确保在客户端关闭cookie时让应用程序重写URL,从而启用会话跟踪。你可以通过调用所有servlet的响应的encodeURL方法来实现。只有当cookie无效时,这个方法才在url中包含唯一标识;从另一个角度讲,这个方法返回的url不会改变。

March 26, 2019 · 1 min · jiezi

访问Web上下文

web组件的上下文是实现了ServletContext接口的一个对象。你可以通过getServletContext方法获取这个对象。这个对象提供了一些方法访问下列信息:初始化参数与web上下文相关的资源对象-值 属性记录功能(???)方法的访问计数是同步的,以预防并发运行的servlet的不兼容的操作。过滤器通过web上下文的getAttribute方法获取访问计数对象。计数器的递增值记录在日志中。

March 26, 2019 · 1 min · jiezi

调用其他web资源

web组件可以直接或间接的调用其他web资源。一个web组件通过内嵌返回客户端内容的另一个web资源的url来间接调用其他web资源。在执行时,一个web资源通过包含另一个资源的内容或者转发请求到另一个资源直接调用。 调用运行web组件服务的一个有效的资源,必须首先通过getRequestDispatcher方法获得一个RequestDispatcher对象。你可以从web上下文或者一个请求对象中获取RequestDispatcher对象;需要注意的是,这两个方法有一些不同的行为。该方法将所请求的路径作为一个参数;请求可能使用相对路径(),但web上下文必须是一个绝对路径。如果资源是无效的,或者服务容器没有为该类型的资源实现RequestDispatcher对象,getRequestDispatcher将返回null。 您的servlet应该准备好处理这种情况。在响应中包含其他资源导入其他web资源是经常使用的,例如广告内容或者版权信息,包含在一个web资源返回的响应中。导入其他web资源,调用RequestDispatcher对象的include方法:include(request, response);如果资源是静态的,include方法启用了程序化的服务端关联。如果资源是一个web组件,这个方法的作用是发送请求到要包含的web组件,执行这个web组件,然后将include包含的servlet响应执行的结果。被包含的组件可以访问请求对象,但它对响应的处理是受限的。它可以写入响应体,并且提交响应它不能设置响应头或者调用任何方法,比如设置cookie,等影响请求头的操作将控制器转移到另一个web资源在某些应用程序中,你可能相对某些web资源做请求的预处理,有另一个组件生成响应。例如,你可能想去部分的处理一个请求,然后根据请求的性质调用另一个web组件。为了控制转发到另一个web资源,你需要调用RequestDispatcher对象的forward方法。当一个请求被转发,请求的url会被设置为转发页面的路径。原始URL和他的构成部分被设置到下面的属性中:javax.servlet.forward.request_urijavax.servlet.forward.context_pathjavax.servlet.forward.servlet_pathjavax.servlet.forward.path_infojavax.servlet.forward.query_string应该使用forward方法为回复用户提供另一个资源责任。如果你已经在servlet内部响应一个ServletOutputStream对象或者PrintWriter对象,你不能使用这个方法;做这个操作,将抛出IllegalStateException异常。

March 26, 2019 · 1 min · jiezi

Filter : 过滤请求和响应

filter对象可以改变请求和响应的头信息和内容信息。过滤器和web组件的不同之处在于,过滤器通常不会自行创建响应。作为替代,过滤器提供附加到任意类型的web资源的功能。因此,过滤器不该对要过滤的web资源有任何依赖。这样,它可以由多种web资源组成。 过滤器可以执行的主要任务如下:查询请求并采取响应措施组织请求-响应对的进一步传递修改请求头和数据。你可以通过设置请求的自定义版本来完成此操作。修改响应头和数据。你可以通过设置响应的自定义版本来完成此操作。与web资源相互作用应用程序的过滤器包含认证、日志、图片转换、数据压缩、数据加密、标记流、xml转换等。 你可以给一个web资源配置0-多个过滤器,并且可以自定义过滤器的顺序。过滤器链在包含此组件的web资源部署时指定,并且在web容器加载的时候实例化。编写filter程序filtering api定义在javax.servlet包中的Filter, FilterChain, and FilterConfig接口中。你可以通过实现Filter接口定义一个过滤器。 使用@WebFilter注解在web程序中定义过滤器。这个注解作用在类上,并且包含过滤器的元数据。过滤器注解必须定义至少一个url匹配,通过使用z注解的urlPatterns或value属性完成这个操作。所有其他的属性都是可选的,有默认设置。当只有一个url规则时使用value注解;当有多个url规则或需要自定义属性时使用urlPatterns注解。 使用@WebFilter 注解的类必须实现 javax.servlet.Filter 接口。 要将配置数据添加到过滤器中,可以使用@WebFilter注解的initParams属性。initParams属性包含一个 @WebInitParam 注解。下面的代码片段定义了一个过滤器,定义了一个初始化参数: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 { …Filter接口的最重要的方法是doFilter,这个方法可以执行下列操作:核查请求头定制请求对象,如果过滤器想要修改请求头或数据定制响应对象,如果过滤器想要修改响应头或数据调用过滤器链的下一个实体。如果当前过滤器是过滤器链的最后一个过滤器,并且结束目标是web资源或静态资源,下一个实体是链末端的资源;否则,下一个实体是war定义的过滤器。过滤器通过调用chain对象的doFilter方法调用下一个实体,传入调用它的请求、响应或它创建的包装版本。换种说法是,filter可以通过不调用下一个实体来阻塞请求。在后一种情况下,过滤器负责填充响应。在调用下一个实体后核查响应头抛出一个错误指示执行流程中的错误执行doFilter,你必须实现init和destroy方法。init方法在web容器实例化的时候调用;如果你想给filter传入初始化参数,可以通过传入init方法的FilterConfig参数获取它们。编写自定义请求和响应代码过滤器有多种方式去修改请求和响应。例如,一个过滤器可以向请求添加一个参数或者在响应中插入数据。 过滤器修改响应必须在响应返回客户端之前捕获响应。为此, 您将一个替代流传递给生成响应的servlet。备用流阻止servlet在完成时关闭原始响应流,并允许过滤器修改servlet的响应。 要将此替换流传递给servlet,过滤器会创建一个响应包装器,它会覆盖getWriter或getOutputStream方法以返回此替换流。这个包装器通过过滤器链doFilter方法传递。包装器方法默认调用包装的请求或响应对象。 重写请求方法,你包装的请求必须继承ServletRequestWrapper或HttpServletRequestWrapper。重写响应方法,你的响应必须继承ServletResponseWrapper or HttpServletResponseWrapper。指定过滤器映射web容器使用请求映射决定给web资源应用具体的过滤器。过滤器映射使用名称映射一个过滤器到web组件或者使用url规则匹配到web资源。过滤器按照war中定义的顺序执行。您可以使用NetBeans IDE或使用XML手动编写列表来为其部署描述符中的WAR指定过滤器映射列表。 如果你想记录每一个到web应用的请求,你可以将过滤器映射到url规则“/”。 可以映射filter到一个或多个web资源,当然你也可以给一个web资源映射多个filter。参见下图,F1映射到S1、S2、S3,F2映射到S2,F3映射到S1、S2. 再次强调,filter chain是传入filter的doFilter方法的一个参数。该链通过过滤器映射间接生成。链中的过滤器顺序与过滤器映射在Web应用程序部署描述符中的显示顺序相同。当一个过滤器映射到S1,web容器调用F1的doFilter方法。S1的过滤器链中每个过滤器的doFilter方法由链中的前一个过滤器通过chain.doFilter方法调用。因为S1的过滤器链包含过滤器F1和F3,所以F1对chain.doFilter的调用会调用过滤器F3的doFilter方法。 当F3的doFilter方法完成时,控制返回F1的doFilter方法。通过NetBeans IDE定义请求映射在Project节点展开应用程序展开Project节点下的Web Pages and WEB-INF节点双击web.xml点击编辑窗口最上方的Filters展开编辑窗口的Servlet Filters节点点击Add Filter Element 添加filter与web资源的url映射关系在添加servlet filter接口,填写filtername点击Browse定位filter适用的servlet点击ok要约束过滤器应用于请求的方式,步骤如下:a. 展开Filter Mappings节点b. 从filterlist中选择一个filterc. 点击addd. 在添加映射弹窗,需要选择一个转发类型:REQUEST:只映射直接从客户端过来的请求ASYNC:只映射直接从客户端过来的的异步async请求FORWARD:只有当请求被转发到组件时INCLUDE : 仅当请求由已包含的组件处理时ERROR:仅在使用错误页面机制处理请求时通过选择多个调度程序类型,可以指示过滤器应用于上述情况的任意组合。 如果未指定类型,则默认选项为REQUEST

March 25, 2019 · 1 min · jiezi

编写Service方法

servlet提供的service方法实现了GenericServlet的service方法,在HttpServlet 对象的doMethod( Get, Delete, Options, Post, Put, or Trace) 方法中,或者在其他实现了Servlet接口的类的方法中。术语service method用来描述Servlet类中的任何能提供给客户端调用的方法的。 通常,service方法用来从请求中读取信息,访问外部资源,然后基于这些信息填充相应数据。对HTTP Servlet来说,正确的填充相应的步骤如下:获取响应数据流填充响应头编写响应数据流的内容响应头必须在响应提交之前设置,web容器将忽略响应提交之后设置响应头或添加响应头的操作。下两节描述如何从请求中获取信息和生成响应。从请求中获取信息请求携带数据从客户端传到服务端。所有请求都实现了ServletRequest接口。这个接口定义的方法可以访问下面的信息:参数,通常用来在客户端与服务端之间传递参数对象属性,通常用来在web容器与servlet之间、多个servlet之间传递信息有关用于传达请求的协议以及请求中涉及的客户端和服务器的信息本地化的相关信息当然你也可以直接获取输入流,并手工解析数据。读取这些数据,最好使用BufferedReader对象获取请求的getReader方法。读取字节流数据,需要使用getInputStream方法返回的ServletInputStream对象。 Http servlet传递一个Http请求对象,HttpServletRequest,它包含请求URL、Http头信息、查询字符串等等。Http URL包含下列信息:http://[host]:[port][request-path]?[query-string]请求路径还包括一下元素:上下文路径 : 使用/符号与web应用程序的跟路径分隔Servlet路径: 请求此路径的别名所对应的路径。路径以/开始。path 路径: 请求路径中不属于上下文路径和servlet上下文的路径你可以使用HttpServletRequest接口的getContextPath, getServletPath, and getPathInfo方法访问这些信息。除url编码与请求路径有区别外,请求路径总是等于上下文路径+servlet路径+path路径。 查询字符串由一组参数和值组成。单个参数可以通过请求的getParameter方法获取。有下面两种方式生成查询字符串:查询字符串可以在web页面上直观的显示当以get方式提交Http请求时,查询字符串附加在了请求后面。构造响应响应包含从服务端传到客户端的数据。所有的响应都实现了ServletResponse接口。这个接口定义的方法支持做下面的工作:发送输出流数据到客户端。发送字符数据,使用getWriter方法返回的PrintWriter对象;发送MIME类型的二进制数据,使用getOutputStream方法返回的ServletOutputStream。混合二进制和字符数据,存在多重响应,需要使用ServletOutputStream类并手动管理字符部分。可以使用setContentType方法指定包含的类型(如text/html)。这个方法必须在响应提交之前调用。缓冲区允许在响应提交之前写入数据,从而允许servlet有更多时间去设置状态代码和响应头或者转发到其他web资源。这个方法必须在任何内容被写入前或响应被提交前。设置本地化信息,比如区域位置和编码,在Chapter 20, “Internationalizing and Localizing Web Applications” 有更详尽的描述。Http响应对象, javax.servlet.http.HttpServletResponse,有表示Http头的属性,如下:状态代码 用于指示不满足请求或请求已重定向的原因。cookies 用来在客户端保存服务器的信息。通常,cookies用户维持单一用户登陆或者是跟踪一个用户的session(查看Session Tracking章节)。

March 25, 2019 · 1 min · jiezi

spring boot 开发soap webservice

介绍spring boot web模块提供了RestController实现restful,第一次看到这个名字的时候以为还有SoapController,很可惜没有,对于soap webservice提供了另外一个模块spring-boot-starter-web-services支持。本文介绍如何在spring boot中开发soap webservice接口,以及接口如何同时支持soap和restful两种协议。soap webserviceWeb service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,既可以是soap webservice也可以是rest webservice,在rest还没出来之前,我们说webservice一般是指基于soap协议进行通信的web应用程序。在开始之前,我觉得有必要了解下soap webservice,具体的概念网上可以找到很多资料,但网上资料概念性较强,而且soap协议使用的是xml进行通信,相信xml里面一个namespace就能吓跑一大堆人,所以这里不讨论具体的soap协议细节,我想通过一个例子来说明什么是soap webservice,通过该例子,你能了解soap webservice其运作原理,当然如果你觉得你对这个已经很了解了,大可跳过本章节,本章节跟后面的内容没有任何关系。假设我们开发了一个web接口,想给别人用,我们要怎么办部署接口到服务器编写接口文档,写清楚接口是通过什么方法调的,输入参数是什么,输出参数是什么,错误时返回什么。那问题来了,我们能不能只把接口部署到服务器上,然后接口不单能提供具体的服务,而且还能自动生成一份标准的接口文档,把接口信息都记录在该文档里,如果能做到,是不是能做到"接口即文档"的目的。那么一个接口的信息包括哪些呢?接口地址接口调用方法接口输入参数接口输出参数接口出错返回信息….soap webservice里wsdl文件就是接口描述信息。核心的信息就是以上几个。第二个问题,由于Web service是一个平台独立,也就是说,使用接口的人不知道这个service是用什么技术开发的,可能是php可能是java等,但接口的参数和返回的数据都是一样的,要达到这种目的,就需要两个东西,一个是跟平台无关的数据格式,soap使用的是xml,一个是通信协议,也就是soap协议。下面就介绍如何不使用任何框架,仅通过servlet实现一个webservice。该webservice功能很简单,就是通过一个人的姓名查询这个人的详细信息。ps:servlet是java web的基础,理解servlet对理解整个java web非常重要,没写过servlet就开始用各种框架写接口就是在胡闹。1. wsdl文件准备以下wsdl文件,不要管这个文件是怎么来的,是怎么生成的,我们这次只讲原理,不谈细节,总之,你根据需求写出了这个wsdl文件。<?xml version=“1.0” encoding=“UTF-8” standalone=“no”?><wsdl:definitions xmlns:wsdl=“http://schemas.xmlsoap.org/wsdl/" xmlns:sch=“http://www.definesys.com/xml/employee" xmlns:soap=“http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns=“http://www.definesys.com/xml/employee" targetNamespace=“http://www.definesys.com/xml/employee"> <wsdl:types> <xs:schema xmlns:xs=“http://www.w3.org/2001/XMLSchema" elementFormDefault=“qualified” targetNamespace=“http://www.definesys.com/xml/employee"> <xs:element name=“EmployeeDetailRequest”> <xs:complexType> <xs:sequence> <xs:element name=“name” type=“xs:string”/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name=“EmployeeDetailResponse”> <xs:complexType> <xs:sequence> <xs:element name=“Employee” type=“tns:Employee”/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name=“Employee”> <xs:sequence> <xs:element name=“name” type=“xs:string”/> <xs:element name=“email” type=“xs:string”/> </xs:sequence> </xs:complexType></xs:schema> </wsdl:types> <wsdl:message name=“EmployeeDetailRequest”> <wsdl:part element=“tns:EmployeeDetailRequest” name=“EmployeeDetailRequest”> </wsdl:part> </wsdl:message> <wsdl:message name=“EmployeeDetailResponse”> <wsdl:part element=“tns:EmployeeDetailResponse” name=“EmployeeDetailResponse”> </wsdl:part> </wsdl:message> <wsdl:portType name=“Employee”> <wsdl:operation name=“EmployeeDetail”> <wsdl:input message=“tns:EmployeeDetailRequest” name=“EmployeeDetailRequest”> </wsdl:input> <wsdl:output message=“tns:EmployeeDetailResponse” name=“EmployeeDetailResponse”> </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name=“EmployeeSoap11” type=“tns:Employee”> <soap:binding style=“document” transport=“http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name=“EmployeeDetail”> <soap:operation soapAction=””/> <wsdl:input name=“EmployeeDetailRequest”> <soap:body use=“literal”/> </wsdl:input> <wsdl:output name=“EmployeeDetailResponse”> <soap:body use=“literal”/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name=“EmployeeService”> <wsdl:port binding=“tns:EmployeeSoap11” name=“EmployeeSoap11”> <soap:address location=“http://localhost:8081/ws-servlet/ws/employee-detail”/> </wsdl:port> </wsdl:service></wsdl:definitions>soap:address location里面端口号需要修改为servlet运行的端口号。从以下xml片段可以看出…<wsdl:binding name=“EmployeeSoap11” type=“tns:Employee”> <soap:binding style=“document” transport=“http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name=“EmployeeDetail”> <soap:operation soapAction=””/> <wsdl:input name=“EmployeeDetailRequest”> <soap:body use=“literal”/> </wsdl:input> <wsdl:output name=“EmployeeDetailResponse”> <soap:body use=“literal”/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name=“EmployeeService”> <wsdl:port binding=“tns:EmployeeSoap11” name=“EmployeeSoap11”> <soap:address location=“http://localhost:8081/ws-servlet/ws/employee-detail”/> </wsdl:port> </wsdl:service>接口名称是EmployeeDetail(wsdl:operation)接口输入参数是EmployeeDetailRequest(wsdl:input)接口输出参数是EmployeeDetailResponse(wsdl:output)接口地址是http://localhost:8081/ws-servlet/ws/employee-detail(soap:address)2. 获取wsdl文件servletpackage com.definesys.demo.servlet;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * @Copyright: Shanghai Definesys Company.All rights reserved. * @Description: * @author: jianfeng.zheng * @since: 2019/1/5 下午1:45 * @history: 1.2019/1/5 created by jianfeng.zheng /public class WsdlServlet extends HttpServlet { public static final String WSDL_XML = “<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://www.definesys.com/xml/employee" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.definesys.com/xml/employee" targetNamespace="http://www.definesys.com/xml/employee">\n” + " <wsdl:types>\n” + " <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.definesys.com/xml/employee">\n” + “\n” + " <xs:element name="EmployeeDetailRequest">\n” + " <xs:complexType>\n” + " <xs:sequence>\n” + " <xs:element name="name" type="xs:string"/>\n" + " </xs:sequence>\n" + " </xs:complexType>\n" + " </xs:element>\n" + “\n” + " <xs:element name="EmployeeDetailResponse">\n" + " <xs:complexType>\n" + " <xs:sequence>\n" + " <xs:element name="Employee" type="tns:Employee"/>\n" + " </xs:sequence>\n" + " </xs:complexType>\n" + " </xs:element>\n" + “\n” + " <xs:complexType name="Employee">\n" + " <xs:sequence>\n" + " <xs:element name="name" type="xs:string"/>\n" + " <xs:element name="email" type="xs:string"/>\n" + " </xs:sequence>\n" + " </xs:complexType>\n" + “\n” + “</xs:schema>\n” + " </wsdl:types>\n" + " <wsdl:message name="EmployeeDetailRequest">\n" + " <wsdl:part element="tns:EmployeeDetailRequest" name="EmployeeDetailRequest">\n" + " </wsdl:part>\n" + " </wsdl:message>\n" + " <wsdl:message name="EmployeeDetailResponse">\n" + " <wsdl:part element="tns:EmployeeDetailResponse" name="EmployeeDetailResponse">\n" + " </wsdl:part>\n" + " </wsdl:message>\n" + " <wsdl:portType name="Employee">\n" + " <wsdl:operation name="EmployeeDetail">\n" + " <wsdl:input message="tns:EmployeeDetailRequest" name="EmployeeDetailRequest">\n" + " </wsdl:input>\n" + " <wsdl:output message="tns:EmployeeDetailResponse" name="EmployeeDetailResponse">\n" + " </wsdl:output>\n" + " </wsdl:operation>\n" + " </wsdl:portType>\n" + " <wsdl:binding name="EmployeeSoap11" type="tns:Employee">\n" + " <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>\n" + " <wsdl:operation name="EmployeeDetail">\n" + " <soap:operation soapAction=""/>\n" + " <wsdl:input name="EmployeeDetailRequest">\n" + " <soap:body use="literal"/>\n" + " </wsdl:input>\n" + " <wsdl:output name="EmployeeDetailResponse">\n" + " <soap:body use="literal"/>\n" + " </wsdl:output>\n" + " </wsdl:operation>\n" + " </wsdl:binding>\n" + " <wsdl:service name="EmployeeService">\n" + " <wsdl:port binding="tns:EmployeeSoap11" name="EmployeeSoap11">\n" + " <soap:address location="http://localhost:8081/ws-servlet/ws/employee-detail"/>\n" + " </wsdl:port>\n" + " </wsdl:service>\n" + “</wsdl:definitions>”; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType(“text/xml”); resp.getOutputStream().write(WSDL_XML.getBytes()); }}是不是很简单,是的,为了简单,我直接将wsdl文件用变量存储,我们还需要配置下web.xmlweb.xml<?xml version=“1.0” encoding=“UTF-8”?><web-app xmlns=“http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version=“3.1”> <servlet> <servlet-name>wsdl</servlet-name> <servlet-class>com.definesys.demo.servlet.WsdlServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>wsdl</servlet-name> <url-pattern>/ws/employee</url-pattern> </servlet-mapping></web-app>这样我们访问http://localhost:8080/ws/employee就能返回一个wsdl文件,也就是接口描述文件。在wsdl文件里,我们定义接口地址为http://localhost:8080/ws/employee-detail,接下来我们就要实现这个接口。3. 业务servletimport javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/* * @Copyright: Shanghai Definesys Company.All rights reserved. * @Description: * @author: jianfeng.zheng * @since: 2019/1/5 下午2:56 * @history: 1.2019/1/5 created by jianfeng.zheng /public class EmployeeServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String response = “<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">\n” + " <SOAP-ENV:Header/>\n” + " <SOAP-ENV:Body>\n” + " <ns2:EmployeeDetailResponse xmlns:ns2="http://www.definesys.com/xml/employee">\n” + " <ns2:Employee>\n" + " <ns2:name>jianfeng</ns2:name>\n" + " <ns2:email>jianfeng.zheng@definesys.com</ns2:email>\n" + " </ns2:Employee>\n" + " </ns2:EmployeeDetailResponse>\n" + " </SOAP-ENV:Body>\n" + “</SOAP-ENV:Envelope>”; resp.getOutputStream().write(response.getBytes()); }}这里不做任何业务处理,不做xml转bean,不做bean转xml,就是这么暴力,直接返回xml,但他仍是一个soap服务,支持所有soap工具调用。将servlet配置到web.xml里web.xml<?xml version=“1.0” encoding=“UTF-8”?><web-app xmlns=“http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version=“3.1”> <servlet> <servlet-name>wsdl</servlet-name> <servlet-class>com.definesys.demo.servlet.WsdlServlet</servlet-class> </servlet> <servlet> <servlet-name>employee</servlet-name> <servlet-class>com.definesys.demo.servlet.EmployeeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>wsdl</servlet-name> <url-pattern>/ws/employee</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>employee</servlet-name> <url-pattern>/ws/employee-detail</url-pattern> </servlet-mapping></web-app>/ws/employee-detail这个地址必须和wsdl文件里定义的保持一致,不然服务无法被找到。4. 测试使用soapui测试我们的webservice,通过地址http://localhost:8081/ws-servlet/ws/employee导入wsdl文件,测试接口,返回我们在业务servlet里面写死的内容。恭喜你,你已经不依赖任何第三方包完成了一个soap webservice。当然这个只是一个玩具,但框架就是在上面的基础上进行扩展,增加wsdl文件自动生成,xml转java,java转xml,xml校验,错误处理等功能,如果你有时间,你也可以写一个soap webservice框架。代码已经上传至github,欢迎star,开始进入正题,偏的有点远。spring boot开发soap webservice1. 创建spring boot工程你可以通过spring initializr初始化spring boot工程,也可以通过inte idea的spring initializr插件进行初始化,个人推荐后面这种。2. 添加依赖添加soap webservice相关依赖包和插件,pom.xml<!–依赖–><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId></dependency><dependency> <groupId>wsdl4j</groupId> <artifactId>wsdl4j</artifactId></dependency>…<!–插件–><plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>1.6</version> <executions> <execution> <id>xjc</id> <goals> <goal>xjc</goal> </goals> </execution> </executions> <configuration> <schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory> <!–<schemaFiles>employee.xsd</schemaFiles>–> <outputDirectory>${project.basedir}/src/main/java</outputDirectory> <packageName>com.definesys.tutorial.ws.type</packageName> <clearOutputDir>false</clearOutputDir> </configuration></plugin>插件jaxb2能够实现java和xml之间互转,下面是几个参数的说明schemaDirectory:xsd文件目录schemaFiles:指定schemaDirectory下的xsd文件,多个用逗号隔开,必须指定schemaDirectoryoutputDirectory:生成java文件保存目录packageName:生成java文件包路径clearOutputDir:重新生成前是否需要清空目录3. 编写xsd文件假设我们的需求是通过员工工号查询员工详细信息,根据需求编写以下xsd文件,并保存在/src/main/resources/目录下。employee.xsd<xs:schema xmlns:xs=“http://www.w3.org/2001/XMLSchema" xmlns:tns=“http://www.definesys.com/xml/employee" targetNamespace=“http://www.definesys.com/xml/employee" elementFormDefault=“qualified”> <xs:element name=“EmployeeDetailRequest”> <xs:complexType> <xs:sequence> <xs:element name=“code” type=“xs:string”/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name=“EmployeeDetailResponse”> <xs:complexType> <xs:sequence> <xs:element name=“Employee” type=“tns:Employee”/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name=“Employee”> <xs:sequence> <xs:element name=“code” type=“xs:string”/> <xs:element name=“name” type=“xs:string”/> <xs:element name=“email” type=“xs:string”/> </xs:sequence> </xs:complexType></xs:schema>4. 生成java类型文件我们需要根据xsd文件生成java类型文件,这就要借助maven插件jaxb2,打开终端运行命令mvn jaxb2:xjc,如果运行正常,就会在目录com.definesys.tutorial.ws.type下生成一堆java文件,此时文件结构如下:.├── java│ └── com│ └── definesys│ └── tutorial│ └── ws│ ├── SpringbootWsApplication.java│ └── type│ ├── Employee.java│ ├── EmployeeDetailRequest.java│ ├── EmployeeDetailResponse.java│ ├── ObjectFactory.java│ └── package-info.java└── resources ├── application.properties ├── employee.xsd ├── static └── templates5. 创建配置文件WebserviceConfig.javapackage com.definesys.tutorial.ws;import org.springframework.boot.web.servlet.ServletRegistrationBean;import org.springframework.context.ApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.ClassPathResource;import org.springframework.ws.config.annotation.EnableWs;import org.springframework.ws.config.annotation.WsConfigurerAdapter;import org.springframework.ws.transport.http.MessageDispatcherServlet;import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;import org.springframework.ws.wsdl.wsdl11.Wsdl11Definition;import org.springframework.xml.xsd.SimpleXsdSchema;import org.springframework.xml.xsd.XsdSchema;/* * @Copyright: Shanghai Definesys Company.All rights reserved. * @Description: * @author: jianfeng.zheng * @since: 2019/1/5 下午4:46 * @history: 1.2019/1/5 created by jianfeng.zheng /@EnableWs@Configurationpublic class WebserviceConfig extends WsConfigurerAdapter { @Bean public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) { MessageDispatcherServlet servlet = new MessageDispatcherServlet(); servlet.setApplicationContext(applicationContext); servlet.setTransformWsdlLocations(true); return new ServletRegistrationBean(servlet, “/ws/”); } @Bean(name = “employee”) public Wsdl11Definition defaultWsdl11Definition(XsdSchema schema) { DefaultWsdl11Definition wsdl = new DefaultWsdl11Definition(); wsdl.setPortTypeName(“EmployeePort”); wsdl.setLocationUri("/ws/employee-detail”); wsdl.setTargetNamespace(“http://www.definesys.com/xml/employee"); wsdl.setSchema(schema); return wsdl; } @Bean public XsdSchema employeeSchema() { return new SimpleXsdSchema(new ClassPathResource(“employee.xsd”)); }}6. 创建业务服务EmployeeSoapController.javapackage com.definesys.tutorial.ws;import com.definesys.tutorial.ws.type.Employee;import com.definesys.tutorial.ws.type.EmployeeDetailRequest;import com.definesys.tutorial.ws.type.EmployeeDetailResponse;import org.springframework.ws.server.endpoint.annotation.PayloadRoot;import org.springframework.ws.server.endpoint.annotation.RequestPayload;import org.springframework.ws.server.endpoint.annotation.ResponsePayload;/** * @Copyright: Shanghai Definesys Company.All rights reserved. * @Description: * @author: jianfeng.zheng * @since: 2019/1/5 下午4:49 * @history: 1.2019/1/5 created by jianfeng.zheng /@Endpointpublic class EmployeeSoapController { private static final String NAMESPACE_URI = “http://www.definesys.com/xml/employee"; @PayloadRoot(namespace = NAMESPACE_URI, localPart = “EmployeeDetailRequest”) @ResponsePayload public EmployeeDetailResponse getEmployee(@RequestPayload EmployeeDetailRequest request) { EmployeeDetailResponse response = new EmployeeDetailResponse(); //这里只作为演示,真正开发中需要编写业务逻辑代码 Employee employee = new Employee(); employee.setName(“jianfeng”); employee.setEmail(“jianfeng.zheng@definesys.com”); employee.setCode(request.getCode()); response.setEmployee(employee); return response; }}与RestController不一样的是,spring boot soap是根据请求报文来指定调用的函数,RestController是根据请求路径来确定。@PayloadRoot就是关键,如本次请求报文如下:<soapenv:Envelope xmlns:soapenv=“http://schemas.xmlsoap.org/soap/envelope/" xmlns:emp=“http://www.definesys.com/xml/employee"> <soapenv:Header/> <soapenv:Body> <emp:EmployeeDetailRequest> <emp:code>?</emp:code> </emp:EmployeeDetailRequest> </soapenv:Body></soapenv:Envelope>xmlns:emp=“http://www.definesys.com/xml/employee"就是@PayloadRoot.namespace,emp:EmployeeDetailRequest对应@PayloadRoot.localPart。理解了这个其他都很好理解。7. 测试使用soapui进行测试,通过地址http://localhost:8080/ws/employee.wsdl导入wsdl文件进行测试。输入报文<soapenv:Envelope xmlns:soapenv=“http://schemas.xmlsoap.org/soap/envelope/" xmlns:emp=“http://www.definesys.com/xml/employee"> <soapenv:Header/> <soapenv:Body> <emp:EmployeeDetailRequest> <emp:code>004</emp:code> </emp:EmployeeDetailRequest> </soapenv:Body></soapenv:Envelope>输出报文<SOAP-ENV:Envelope xmlns:SOAP-ENV=“http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <ns2:EmployeeDetailResponse xmlns:ns2=“http://www.definesys.com/xml/employee"> <ns2:Employee> <ns2:code>004</ns2:code> <ns2:name>jianfeng</ns2:name> <ns2:email>jianfeng.zheng@definesys.com</ns2:email> </ns2:Employee> </ns2:EmployeeDetailResponse> </SOAP-ENV:Body></SOAP-ENV:Envelope>同时提供soap和restful两种服务soap一般在企业内部用的比较多,做系统间的集成,restful一般用于移动应用和h5应用,如果在企业应用开发里能够同时提供两种协议的支持,将极大提高接口的复用。其实也没有想象中的那么复杂,在本例中,只需把业务逻辑部分用service实现再创建一个RestController即可,通过设计模式即可解决,不需要引入新的技术。EmployeeService.javapackage com.definesys.tutorial.ws;import com.definesys.tutorial.ws.type.Employee;import com.definesys.tutorial.ws.type.EmployeeDetailRequest;import com.definesys.tutorial.ws.type.EmployeeDetailResponse;import org.springframework.stereotype.Service;/* * @Copyright: Shanghai Definesys Company.All rights reserved. * @Description: * @author: jianfeng.zheng * @since: 2019/1/5 下午5:42 * @history: 1.2019/1/5 created by jianfeng.zheng /@Servicepublic class EmployeeService { public EmployeeDetailResponse getEmployee(EmployeeDetailRequest request) { EmployeeDetailResponse response = new EmployeeDetailResponse(); //这里只作为演示,真正开发中需要编写业务逻辑代码 Employee employee = new Employee(); employee.setName(“jianfeng”); employee.setEmail(“jianfeng.zheng@definesys.com”); employee.setCode(request.getCode()); response.setEmployee(employee); return response; }}EmployeeSoapController.javapackage com.definesys.tutorial.ws;import com.definesys.tutorial.ws.type.Employee;import com.definesys.tutorial.ws.type.EmployeeDetailRequest;import com.definesys.tutorial.ws.type.EmployeeDetailResponse;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.ws.server.endpoint.annotation.Endpoint;import org.springframework.ws.server.endpoint.annotation.PayloadRoot;import org.springframework.ws.server.endpoint.annotation.RequestPayload;import org.springframework.ws.server.endpoint.annotation.ResponsePayload;/* * @Copyright: Shanghai Definesys Company.All rights reserved. * @Description: * @author: jianfeng.zheng * @since: 2019/1/5 下午4:49 * @history: 1.2019/1/5 created by jianfeng.zheng /@Endpointpublic class EmployeeSoapController { @Autowired private EmployeeService service; private static final String NAMESPACE_URI = “http://www.definesys.com/xml/employee"; @PayloadRoot(namespace = NAMESPACE_URI, localPart = “EmployeeDetailRequest”) @ResponsePayload public EmployeeDetailResponse getEmployee(@RequestPayload EmployeeDetailRequest request) { return service.getEmployee(request); }}EmployeeRestController.javapackage com.definesys.tutorial.ws;import com.definesys.tutorial.ws.type.EmployeeDetailRequest;import com.definesys.tutorial.ws.type.EmployeeDetailResponse;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;/* * @Copyright: Shanghai Definesys Company.All rights reserved. * @Description: * @author: jianfeng.zheng * @since: 2019/1/5 下午5:43 * @history: 1.2019/1/5 created by jianfeng.zheng */@RestController@RequestMapping(value = “/rest”)public class EmployeeRestController { @Autowired private EmployeeService service; @RequestMapping(value = “/employee-detail”, method = RequestMethod.POST) public EmployeeDetailResponse getEmployeeDetail(@RequestBody EmployeeDetailRequest request) { return service.getEmployee(request); }}测试$ curl http://localhost:8080/rest/employee-detail -X POST -d ‘{“code”:“004”}’ -H “Content-Type: application/json”{ “employee”: { “code”: “004”, “name”: “jianfeng”, “email”: “jianfeng.zheng@definesys.com” }}这样就实现了soap和rest同时提供的目的。本文代码已提交至gitlab欢迎star相关参考文档https://spring.io/guides/gs/producing-web-service/https://github.com/wls1036/tutorial-springboot-soaphttps://github.com/wls1036/pure-ws-servlet ...

January 5, 2019 · 5 min · jiezi