当前位置: 首页 > news >正文

网站开发环境和运行环境制作网页一般需要兼容哪些软件

网站开发环境和运行环境,制作网页一般需要兼容哪些软件,网站开发的原理,网站建设推广ppt模板文章目录 前情提要解决方案自定义 HttpServletRequest 包装类 RequestWrapper自定义 HttpServletResponse 包装类 ResponseWrapper自定义过滤器 MiddlewareFilter配置过滤器注解配置类 编写 Controller 测试 前情提要 在项目中需要使用过滤器 在请求调用 Controller 方法前修改… 文章目录 前情提要解决方案自定义 HttpServletRequest 包装类 RequestWrapper自定义 HttpServletResponse 包装类 ResponseWrapper自定义过滤器 MiddlewareFilter配置过滤器注解配置类 编写 Controller 测试 前情提要 在项目中需要使用过滤器 在请求调用 Controller 方法前修改请求参数和在结果返回之前修改返回结果。 在 Controller 中定义如下接口 PostMapping(/hello) public JSONObject hello(RequestBody MapString, Object params) {return JSONObject.parseObject(JSON.toJSONString(params)); }定义的过滤器如下 public class ServNoFilter extends OncePerRequestFilter {Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {// 获取请求体内容String requestBody getRequestBody(httpServletRequest);// 业务处理......// 放行filterChain.doFilter(httpServletRequest, httpServletResponse);}private String getRequestBody(HttpServletRequest request) throws IOException {BufferedReader reader new BufferedReader(request.getReader());StringBuilder sb new StringBuilder();String line;while ((line reader.readLine()) ! null) {sb.append(line);}return sb.toString();} }此时启动项目访问接口则会在控制台打印如下异常信息Request processing failed; nested exception is java.lang.IllegalStateException: getReader() has already been called for this request。 表示在过滤器中已经通过 request.getReader() 方法将请求流读取。 如果在过滤器中将 getReader() 换成 getInputStream() 就会报请求体为空异常org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing。 这是因为在 Servlet 中请求对象的输入流只能被读取一次。而在第一次读取请求体时Servlet 容器会将请求体保存在内存中并将其解析成相应的请求参数和请求头信息。如果在后续的处理中再次读取请求体就可能会导致数据错误或异常。 解决方案 自定义 HttpServletRequest 包装类 RequestWrapper 在 Servlet 中原始的 HttpServletRequest 对象中的请求流即请求体只能读取一次。这是因为 HTTP 协议是基于流的协议服务器在读取请求流时会将其消耗掉一旦读取完毕就无法再次读取 当 Servlet 容器读取完请求流后会将请求的内容解析并储存在相应的属性中如请求参数、请求头信息等。在后续的处理过程中Servlet 可以从这些属性中获取请求内容而不必再次读取请求流。 因此我们需要自定义 RequestWrapper 将请求流保存下来并提供方法来多次读取请求体的内容。 自定义 HttpServletRequest 包装类 RequestWrapper 如下 /*** HttpServletRequest 包装类允许在 Servlet 中多次读取请求体内容* 重写了 getInputStream()方法和 getReader() 方法返回可以多次读取的流。*/ public class RequestWrapper extends HttpServletRequestWrapper {private final byte[] body;/*** 构造 RequestWrapper 对象** param request 原始 HttpServletRequest 对象* param context 请求体内容*/public RequestWrapper(HttpServletRequest request, String context) {super(request);this.body context.getBytes(StandardCharsets.UTF_8);}/*** 重写 getInputStream 方法返回经过包装后的 ServletInputStream 对象** return 经过包装后的 ServletInputStream 对象*/Overridepublic ServletInputStream getInputStream() {return new ServletInputStreamWrapper(new ByteArrayInputStream(body));}/*** 重写 getReader 方法返回经过包装后的 BufferedReader 对象** return 经过包装后的 BufferedReader 对象*/Overridepublic BufferedReader getReader() {return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8));}/*** 私有内部类用于包装 ServletInputStream 对象*/private static class ServletInputStreamWrapper extends ServletInputStream {private final ByteArrayInputStream inputStream;/*** 构造函数传入待包装的 ByteArrayInputStream 对象** param inputStream 待包装的 ByteArrayInputStream 对象*/public ServletInputStreamWrapper(ByteArrayInputStream inputStream) {this.inputStream inputStream;}/*** 重写 read 方法读取流中的下一个字节** return 读取到的下一个字节如果已达到流的末尾则返回-1*/Overridepublic int read() {return inputStream.read();}/*** 覆盖 isFinished 方法指示流是否已完成读取数据** return 始终返回 false表示流未完成读取数据*/Overridepublic boolean isFinished() {return false;}/*** 重写 isReady 方法指示流是否准备好进行读取操作** return 始终返回 false表示流未准备好进行读取操作*/Overridepublic boolean isReady() {return false;}/*** 重写 setReadListener 方法设置读取监听器** param readListener 读取监听器*/Overridepublic void setReadListener(ReadListener readListener) {}} }自定义 HttpServletResponse 包装类 ResponseWrapper 与请求流即请求体一样原始的 HttpServletResponse 对象中的响应流即响应体只能写入一次。当服务器在向客户端发送响应时会将响应流写入到网络传输通道中一旦写入完毕就无法再次修改或写入。 因此我们需要通过自定义 ResponseWrapper 包装原始的 HttpServletResponse 对象并重写其输出流或者输出写方法从而实现对响应流的修改和控制。 自定义 HttpServletResponse 包装类 ResponseWrapper 如下 /*** HttpServletResponse 包装类对提供对响应数据的处理和操作。*/ public class ResponseWrapper extends HttpServletResponseWrapper {private final ByteArrayOutputStream outputStream;private ServletOutputStream servletOutputStream;private PrintWriter writer;/*** 构造函数传入原始的 HttpServletResponse 对象** param response 原始的 HttpServletResponse 对象*/public ResponseWrapper(HttpServletResponse response) {super(response);this.outputStream new ByteArrayOutputStream();}/*** 重写 getOutputStream 方法返回经过包装后的 ServletOutputStream 对象** return 经过包装后的 ServletOutputStream 对象*/Overridepublic ServletOutputStream getOutputStream() {if (servletOutputStream null) {servletOutputStream new ServletOutputStreamWrapper(outputStream);}return servletOutputStream;}/*** 重写 getWriter 方法返回经过包装后的 PrintWriter 对象** return 经过包装后的 PrintWriter 对象*/Overridepublic PrintWriter getWriter() {if (writer null) {writer new PrintWriter(getOutputStream());}return writer;}/*** 获取响应数据并指定字符集** param charsetName 字符集名称* return 响应数据字符串*/public String getResponseData(String charsetName) {Charset charset Charset.forName(charsetName);byte[] bytes outputStream.toByteArray();return new String(bytes, charset);}/*** 设置响应数据并指定字符集** param responseData 响应数据字符串* param charsetName 字符集名称*/public void setResponseData(String responseData, String charsetName) {Charset charset Charset.forName(charsetName);byte[] bytes responseData.getBytes(charset);outputStream.reset();try {outputStream.write(bytes);} catch (IOException e) {// 处理异常}setCharacterEncoding(charsetName);}/*** 私有内部类用于包装 ServletOutputStream 对象*/private static class ServletOutputStreamWrapper extends ServletOutputStream {private final ByteArrayOutputStream outputStream;/*** 构造函数传入待包装的 ByteArrayOutputStream 对象** param outputStream 待包装的 ByteArrayOutputStream 对象*/public ServletOutputStreamWrapper(ByteArrayOutputStream outputStream) {this.outputStream outputStream;}/*** 重写 write 方法将指定字节写入输出流** param b 字节*/Overridepublic void write(int b) {outputStream.write(b);}/*** 重写 isReady 方法指示输出流是否准备好接收写入操作** return 始终返回 false表示输出流未准备好接收写入操作*/Overridepublic boolean isReady() {return false;}/*** 重写 setWriteListener 方法设置写入监听器** param writeListener 写入监听器*/Overridepublic void setWriteListener(WriteListener writeListener) {}} }自定义过滤器 MiddlewareFilter 我们的需求是在请求到达服务器之前对请求参数进行修改在响应返回之前对响应结果进行处理。 对于这样的需求我们可以通过自定义过滤器来实现。大致实现思路如下 修改请求参数请求体我们可以 获取请求体内容。修改请求体内容。将修改后的请求对象替换原来的请求对象以便后续获取修改后的参数。 修改响应结果响应体我们可以 获取响应数据。对响应数据进行处理。将修改后的数据作为最终结果返回。 同时为了确保每个请求在请求时只会被过滤一次我们可以继承 OncePerRequestFilter 来定义自己的过滤器。 最终自定义过滤器如下 public class MiddlewareFilter extends OncePerRequestFilter {Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {// 1. 从 HttpServletRequest 对象中获取请求体内容String requestBody getRequestBody(httpServletRequest);// 2. 解析请求体内容为JSON对象JSONObject jsonBody JSONObject.parseObject(requestBody);// 3. 修改请求体内容jsonBody.put(paramKey,paramValue);// 4. 包装 HttpServletRequest 对象为自定义的 RequestWrapper 对象以便后续的处理RequestWrapper requestWrapper new RequestWrapper(httpServletRequest, jsonBody.toJSONString());// 5. 包装 HttpServletResponse 对象为自定义的 ResponseWrapper 对象以便后续的处理ResponseWrapper responseWrapper new ResponseWrapper(httpServletResponse);// 6. 调用下一个过滤器或 ServletfilterChain.doFilter(requestWrapper, responseWrapper);// 7. 获取响应数据String responseData responseWrapper.getResponseData(StandardCharsets.UTF_8.name());// 8. 解析响应数据为JSON对象JSONObject jsonData JSONObject.parseObject(responseData);// 9. 在这里可以对响应数据进行处理jsonData.put(responseKey, responseValue);// 10. 将修改后的 JSON 对象转换为字符串responseData jsonData.toJSONString();// 11. 将修改后的 JSON 对象设置为最终的响应数据responseWrapper.setResponseData(responseData, StandardCharsets.UTF_8.name());// 12. 将响应数据写入原始的响应对象解决响应数据无法被多个过滤器处理问题OutputStream outputStream httpServletResponse.getOutputStream();outputStream.write(responseData.getBytes(StandardCharsets.UTF_8));outputStream.flush();}/*** 获取请求体内容。** param request HttpServletRequest对象* return 请求体内容* throws IOException 如果读取请求体内容时发生I/O异常*/private String getRequestBody(HttpServletRequest request) throws IOException {BufferedReader reader new BufferedReader(new InputStreamReader(request.getInputStream()));StringBuilder sb new StringBuilder();String line;while ((line reader.readLine()) ! null) {sb.append(line);}return sb.toString();} }配置过滤器 注解 通过 Java Servlet 3.0 规范中引入的 WebFilter 注解配置过滤器。 WebFilter 注解可以应用在实现了 Filter 接口或继承自 OncePerRequestFilter 的类上标识该类为过滤器并指定过滤器的相关配置包括拦截的 URL 路径、执行顺序以及初始化参数等。 我们可以在 MiddlewareFilter 过滤器上使用 WebFilter 注解注册该过滤器并指定执行该过滤器执行的顺序和拦截的 URL WebFilter(value 1000, urlPatterns /hello) public class MiddlewareFilter extends OncePerRequestFilter {...... }value设置过滤器的执行顺序数字越小优先级越高。urlPatterns指定要拦截的 URL 路径允许指定多个 URL 路径urlPatterns {/hello,/hello1}。 还需要再启动类上使用ServletComponentScan注解扫描和注册带有 WebServlet、WebFilter 和 WebListener 注解的组件 ServletComponentScan SpringBootApplication public class Demo1Application {public static void main(String[] args) {SpringApplication.run(Demo1Application.class, args);}}配置类 除了注解的形式配置过滤器我们还可以通过配置类的形式进行配置。 创建 FilterConfig 类用于配置需要注册的过滤器同时在类上添加 Configuration 注解标识该类为配置类在项目启动时 Spring 会自动扫描该类中的 Bean 定义并将其加载到容器中 Configuration public class FilterConfig {Beanpublic FilterRegistrationBeanMiddlewareFilter middlewareFilter() {FilterRegistrationBeanMiddlewareFilter registration new FilterRegistrationBean();registration.setFilter(new MiddlewareFilter()); // 设置过滤器实例registration.addUrlPatterns(/hello); // 拦截的 URL 路径registration.setOrder(1000); // 设置过滤器执行顺序数字越小越先执行return registration;}}在类中我们定义了名为 middlewareFilter 的方法用于注册我们自定义的 MiddlewareFilter 过滤器。 在 方法中创建了一个 FilterRegistrationBean 对象用于注册和配置过滤器并设置 MiddlewareFilter 对象作为过滤器实例指定了过滤器要拦截的 URL 路径滤器执行顺序。 最后将 FilterRegistrationBean 对象返回以便 Spring 自动进行注册和管理。 编写 Controller 测试 创建两个接口同样的逻辑接收一个请求体参数 params再将接收的参数以 JSON 格式返回 RestController public class BasicController {/*** 处理 /hello 请求的方法* param params 请求体参数以键值对的形式传递* return 经过转换后的 JSONObject 对象*/PostMapping(/hello)public JSONObject hello(RequestBody MapString, Object params) {return JSONObject.parseObject(JSON.toJSONString(params));}PostMapping(/hello1)public JSONObject hello1(RequestBody MapString,Object params) {return JSONObject.parseObject(JSON.toJSONString(params));} }启动项目在 ApiFox 中分别以同样的请求参数发送 POST 请求调用 /hello、/hello1 接口 请求参数 {name: hello,age: 20 }/hello 接口返回结果 {paramKey: paramValue,responseKey: responseValue,name: hello,age: 20 }/hello1 接口返回结果 {name: hello,age: 20 }复制多个 MiddlewareFilter 过滤器模拟多层过滤器修改请求体参数和返回结果测试结果如下 {paramKey: paramValue, //过滤器1responseKey2: responseValue2, //过滤器2responseKey: responseValue, //过滤器2paramKey2: paramValue2, //过滤器1name: hello,age: 20 }
http://www.hkea.cn/news/14478848/

相关文章:

  • 可以帮别人备案网站吗为什么要做网站优化
  • 服装网站目标ui交互设计是什么意思呢
  • 沈阳网站备案查询网站制作xiu021
  • 网站建设ps模板下载2019年做网站还有机会吗
  • 比较好的做简历的网站全球设计公司排名
  • 做网站官网扶余市建设局网站
  • 毕节建设公司网站网络广告例子
  • 哪个网站可以做兼职笔译自学网站查分数
  • 网站开发职业环境分析南宁中庭装饰公司电话
  • 自己做蛋糕有什么网站吗商品列表页面html模板
  • asp.net网站入侵实时新闻
  • 象客企业网站做优化排名网站在线沟通工具
  • 东营外贸型网站设计江苏seo平台
  • 富阳网站优化win7 iis创建网站
  • 网站建设的问题中国知名设计网站
  • 展览网站建设免费拿项目做的网站
  • 赣州做网站的大公司外贸建站源码
  • 中学生做的网站有哪些方面威海住房建设部官方网站
  • 个人电脑做服务器映射网站做网站能创业吗
  • 天津做网站优化哪家好网站建设捌金手指下拉二七
  • 网站运行平台包括建设网站后需要什么知识
  • wordpress建电商网站嘉兴网站建设seo
  • 洛宁县东宋乡城乡建设局网站安卓开发需要掌握哪些技术
  • 镇海区建设工程安监站网站互联网营销的十五种方式
  • 作品集网站代码企业网站建设选题依据
  • 台州优秀网站设计网站开发完后部署到网上
  • 专业的led网站建设电影下载网站模板
  • dede 购物网站淮北招聘网
  • 做网站补贴临沂网站设计公司
  • 中华建设杂志网站上海网站 备案查询