介绍本篇内容前,先抛出我遇到的问题或者说是需求!(精读阅读本篇可能花费您15分钟,略读需5分钟左右)

一:需求说明

有一个Controller有两个方法第一个方法通过指定的路径和参数去渲染jsp内容,并返回html数据第二个方法获取第一个方法中的html进行封装现在的做法是在第二个方法通过发送Http请求获取数据,然后返回进行封装!
问题:
需要优化的是 不通过Http请求,第二个方法可以拿到第一个方法中的Html数据

二:简化例子(待优化的例子)

注:使用的SpringMVC框架,使用贴出视图解析器 配置文件

<!-- 默认的视图解析器 在上边的解析错误时使用 (默认使用html)- --><bean id="defaultViewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver"p:order="2"><property name="viewClass"value="org.springframework.web.servlet.view.JstlView" /><property name="contentType" value="text/html" /><property name="prefix" value="/WEB-INF/jsp/" /><property name="suffix" value=".jsp" /></bean>
1.简化请求图示说明

简单说明:一个Controller中有三个方法,访问/index 返回html输出到页面,
浏览器页面显示内容为:

 hello url = http://blog.csdn.net/u010648555world  url = http://blog.csdn.net/u010648555

/index中通过Http去请求/hello ,渲染hello.jsp 返回 hello.jsp 对应的html代码,去请求/world ,渲染world.jsp 返回 world..jsp 对应的html代码!

2.简化代码说明

(1):Java代码

package com.dufy.web;import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Created by dufy on 2017/3/21.*/@Controller
public class JspController {/*** 跳转到WEB_INF/jsp/welcome/index.jsp* @param request* @param response* @return*/@RequestMapping("/index")public String index(HttpServletRequest request ,HttpServletResponse response) {List<String> list = new ArrayList<String>();list.add("hello");list.add("wrold");String commonUrl = "http://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath();StringBuilder pageHtml = new StringBuilder();//使用StringBuilder拼接字符串效率高if (list != null && list.size() > 0) {for (String str : list) {StringBuffer paramsBuffer = new StringBuffer();//线程安全paramsBuffer .append(str + "=" + str);//hello=hello  world=world//如果参数中url 需要使用URLEncoderparamsBuffer .append("url"+ "=" + URLEncoder.encode("http://blog.csdn.net/u010648555"));//使用post请求 ,后台获取每个接口方法对应生成的htmlString urlStr = commonUrl +"/" + str + "?jsppath=" + str;//reqest url 这里会调用 /hello  /worldString urlSourceResult = getURLSourcePost(urlStr,paramsBuffer.toString());pageHtml.append(urlSourceResult);}}request.setAttribute("pageHtml",pageHtml);return "welcome/index";}/*** 跳转到WEB_INF/jsp/welcome/hello.jsp* @param request* @param response* @return*/@RequestMapping(value = "/hello",method = RequestMethod.POST)public String hello(HttpServletRequest request,HttpServletResponse response){String jsppath = request.getParameter("jsppath");//处理一些业务逻辑Map<String,String> params = new HashMap<>();for (Object p : request.getParameterMap().keySet()) {try {String s = request.getParameter(p.toString());params.put(p.toString(), s);} catch (Exception e) {e.printStackTrace();}}request.setAttribute("params",params);return "welcome/" + jsppath;}/*** 跳转到WEB_INF/jsp/welcome/world.jsp* @param request* @param response* @return*/@RequestMapping(value = "/wrold" ,method = RequestMethod.POST)public String world(HttpServletRequest request,HttpServletResponse response){String jsppath = request.getParameter("jsppath");//处理一些业务逻辑Map<String,String> params = new HashMap<>();for (Object p : request.getParameterMap().keySet()) {try {String s = request.getParameter(p.toString());params.put(p.toString(), s);} catch (Exception e) {e.printStackTrace();}}request.setAttribute("params",params);return "welcome/" + jsppath;}/*** 通过网站域名URL使用POST方式 获取该网站的源码* @param url 请求的地址* @param param 请求的参数* @return 返回请求的结果*/private  String getURLSourcePost(String url,String param) {PrintWriter out = null;BufferedReader in = null;StringBuilder htmlResult = new StringBuilder();try{URL realUrl = new URL(url);//打开和URL之间的连接HttpURLConnection conn = (HttpURLConnection)realUrl.openConnection();//设置请求的方式conn.setRequestMethod("POST");conn.setConnectTimeout(5 * 1000);//设置通用的请求属性conn.setRequestProperty("accept", "*/*");conn.setRequestProperty("connection", "Keep-Alive");conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");// charset=UTF-8以防止乱码!conn.setRequestProperty("content-type", "application/x-www-form-urlencoded; charset=UTF-8");//发送POST请求必须设置如下两行conn.setDoOutput(true);conn.setDoInput(true);//获取URLConnection对象对应的输出流out = new PrintWriter(conn.getOutputStream());//发送请求参数out.print(param);//flush输出流的缓冲out.flush();//定义BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(conn.getInputStream()));String line;while ((line = in.readLine())!= null){if(StringUtils.isNotBlank(line)){htmlResult.append("\n" + line);}}}catch(Exception e){throw new RuntimeException("发送POST请求出现异常!",e);}//使用finally块来关闭输出流、输入流finally{try{if (out != null){out.close();}if (in != null){in.close();}}catch (IOException ex){ex.printStackTrace();}}return htmlResult.toString();}}

(2):对于的JSP页面

a:index.jsp

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>welcome index</title>
</head>
<body>${pageHtml}
</body>
</html>

b:hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<%@ page import="java.net.URLDecoder" %><%Map<String, String> params = (Map<String, String>)request.getAttribute("params");String hello = params.get("hello");String url = URLDecoder.decode(params.get("url")); //URl解码out.print("<p> " + hello + " </p>");out.print("<p> " + url + " </p>");
%>

c:wrold.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<%@ page import="java.net.URLDecoder" %><%Map<String, String> params = (Map<String, String>)request.getAttribute("params");String world = params.get("world");String url = URLDecoder.decode(params.get("url")); //URl解码out.print("<p> " + world+ " </p>");out.print("<p> " + url + " </p>");
%>

3.待解决(优化)的问题说明
如图是在上面的基础上要进行的优化图!

简单说明,优化方法不使用Http请求,调用/index 可以直接拿到hello.jsp和world.jsp的内容,有什么好的办法能够动态获取JSP的内容呢???思考ing……………

注:可能有人会说,不就是输出

 hello url = http://blog.csdn.net/u010648555world  url = http://blog.csdn.net/u010648555

需要搞的这么复杂吗。直接使用 在方法里面返回对应的字符串不就好了,对不起,我这里只是举个例子,我实际情况就是需要从jsp中渲染动态获取html字符串!

三:优化后代码(使用RequestDispatcher.include()和HttpServletResponseWrapper获取JSP内容)

上面举例子只是为了说明这个需求,下面贴出解决方案,若看博文的你有其他好的办法,可以添加左侧QQ群和我进行讨论!
实现原理简单说明:

在不跳转下访问目标jsp。就是利用RequestDispatcher.include(ServletRequest request, ServletResponse response)。 该方法把RequestDispatcher指向的目标页面写到response中。利用HttpServletResponseWrapper封装HttpServletResponse,使HttpServletResponse采用我们自己定义的输入流(OutputStream)。这样,我们就可以通过这个OutputStream得到目标jsp页面内容。

代码如下:

a:优化Controller

package com.dufy.web;import com.aebiz.pub.util.JspToHtmlUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Created by dufy on 2017/3/21.*/
@Controller
public class JsptoHtmlController {@RequestMapping("/index")public String testJsp(HttpServletResponse response,HttpServletRequest request){StringBuilder pageHtml = new StringBuilder();//使用StringBuilder拼接字符串效率高List<String> list = new ArrayList<>();list.add("/WEB-INF/jsp/welcome/hello.jsp");list.add("/WEB-INF/jsp/welcome/world.jsp");try {if (list != null && list.size() > 0) {for (String str : list) {Map<String,String> params = new HashMap<String,String>();params.put(str,str);//put(hello,hello);//如果参数中url 需要使用URLEncoderparams.put("url",URLEncoder.encode("http://blog.csdn.net/u010648555"));request.setAttribute("params",params);String jspOutput = JspToHtmlUtil.getJspOutput(str, request, response);pageHtml.append(jspOutput);}}} catch (Exception e) {e.printStackTrace();}request.setAttribute("pageHtml",pageHtml);return "welcome/index";}}

b:JspToHtmlUtil

package com.dufy.util;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** Created by dufy on 2017/3/22.*/
public class JspToHtmlUtil {/*** 根据JSP所在的路径获取JSP的内容<br/>* 在不跳转下访问目标jsp。就是利用RequestDispatcher.include(ServletRequest request, ServletResponse response)。* 该方法把RequestDispatcher指向的目标页面写到response中。* @param jspPath jsp路径* @param request HttpServletRequest对象* @param response HttpServletResponse对象* @return* @throws Exception*/public static String getJspOutput(String jspPath, HttpServletRequest request, HttpServletResponse response)throws Exception{WrapperResponse wrapperResponse = new WrapperResponse(response);request.getRequestDispatcher(jspPath).include(request, wrapperResponse);return wrapperResponse.getContent();}
}

注: RequestDispatcher接口中定义了两个方法forward和include,这两个方法都可以将第一个Servlet的请求转发给第二个Servlet,所不同的是forward方法在转发请求后,第一个Servlet的响应终止而由第二个Servlet负责响应输出,而include方法则是在转发请求并且第二个Servlet响应后将响应并入第一个Servlet中,仍然由第一个Servlet负责响应输出(注意调用include方法时两个Servlet的响应输出编码最好保持一致否则可能会出现乱码.

c:WrapperResponse .java

package com.dufy.util;import org.apache.log4j.Logger;import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;/*** Created by dufy on 2017/3/21.<p/>*利用HttpServletResponseWrapper封装HttpServletResponse,使HttpServletResponse采用我们自己定义的输入流(OutputStream)。<p/>* 这样,我们就可以通过这个OutputStream得到目标jsp页面内容。*/
public class WrapperResponse extends HttpServletResponseWrapper {private Logger log = Logger.getLogger(WrapperResponse.class);private MyPrintWriter tmpWriter;private ByteArrayOutputStream output;public WrapperResponse(HttpServletResponse httpServletResponse) {super(httpServletResponse);output = new ByteArrayOutputStream();;// 真正存储数据的返回流(保存数据返回的结果)tmpWriter = new MyPrintWriter(output);}public String getContent() {String str = "";try {//刷新该流的缓冲,详看java.io.Writer.flush()tmpWriter.flush();str = tmpWriter.getByteArrayOutputStream().toString("utf-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();log.error("不支持的编码异常,Unsupported Encoding Exception!");}finally {try {output.close();tmpWriter.close();} catch (IOException e) {e.printStackTrace();log.error("释放资源异常,release resource error!");}}return str;}//覆盖getWriter()方法,使用我们自己定义的Writerpublic PrintWriter getWriter() throws IOException {return tmpWriter;}public void close() throws IOException {tmpWriter.close();}//自定义PrintWriter,为的是把response流写到自己指定的输入流当中//而非默认的ServletOutputStreamprivate static class MyPrintWriter extends PrintWriter {ByteArrayOutputStream myOutput;//此即为存放response输入流的对象public MyPrintWriter(ByteArrayOutputStream output) {super(output);myOutput = output;}public ByteArrayOutputStream getByteArrayOutputStream() {return myOutput;}}
}

d:Jsp保持不变,和之前一样,不需要进行修改

四:why write this article,why not use http request ?

1:使用Http发起请求返回数据,这是最容易想到的方法,实现起来也简单!(只是感觉简单而已)
2:使用Http发起请求,涉及到网络层,此时就会有网络问题出现,网络策略有问题的话,可能导致无法访问数据,假若网络是通的,http请求也是有延时(延时在网络中存在很常见,可能导致代码因为超时出错)。
3:通过上面两点,也就是为什么不适用Http请求返回数据,也就是这篇博文为了实现(优化)功能需要而进行的思考!

4:建议 系统内部调用,最好不要用Http,如果可以的话,请使用rpc的方式,效果和使用起来更好!

五:参考文章


如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
祝你今天开心愉快!


欢迎访问我的csdn博客,我们一同成长!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

博客首页:http://blog.csdn.net/u010648555

SpringMVC——使用RequestDispatcher.include()和HttpServletResponseWrapper动态获取jsp输出内容相关推荐

  1. php获取页面输出内容,PHP CURL获取页面内容输出例子

    使用PHP curl获取页面内容或提交数据,有时候希望返回的内容作为变量储存,而不是直接输出.这个时候就必需设置curl的CURLOPT_RETURNTRANSFER选项为1或true. 1.curl ...

  2. nacos整合springmvc:解决使用@Value或@NacosValue无法从nacos配置中心动态获取最新配置数据问题

    nacos整合springmvc:解决使用@Value或@NacosValue无法从nacos配置中心动态获取最新配置数据问题 1.出现无法动态获取最新配置数据的项目配置: (1)使用的nacos-s ...

  3. 驱动下通过进程PID获得进程名 (动态获取ImageFileName在EPROCESS结构体中的相对偏移)...

    思路 进程EPROCESS结构体中含有进程名ImageFileName(需求处ImageFileName在EPROCESS结构体中的相对偏移)-->获得进程EPROCESS-->通过进程句 ...

  4. 【瑞芯微Rockchip Linux平台】SoftAp需求实现(3)动态获取BT Mac地址并更新beacon帧中的mac信息

    [瑞芯微Rockchip Linux平台]SoftAp需求实现(3)动态获取BT Mac地址并更新beacon帧中的mac信息 1. 获取本机的蓝牙mac地址 __get_bt_mac_addr() ...

  5. C++使用switch动态获取函数(通过函数指针实现)

    C++使用switch动态获取函数(通过函数指针实现) 基本的就不再赘述了,以下使用三种方法完成根据不同情况动态获取函数的功能. 方法一:通过形参取地址获得函数指针 这种方式的好处是可以通过传入多个取 ...

  6. 织梦php调用当前文章关键词,dedecms动态获取当前文章关键词关联相关文章,提升SEO优化内容关键词相关度...

    摘要:dedecms系统使用默认的关键词关联相关文章时,关键词是写死不能变的,这样局限性太大了,如果把固定关键词替换为动态获取当前文章的关键词就更方便了-- dedecms默认可以使用arclist里 ...

  7. android 动态获取权限有哪些,Android 6.0+ 动态获取权限

    Android 6.0+ 动态获取权限 这里有一个现成的库,可以直接拿来用.方便简单 1.向app下的gradle添加依赖: dependencies{ // android 6.0+ 动态获取权限 ...

  8. 【java】java反射机制,动态获取对象的属性和对应的参数值,并属性按照字典序排序,Field.setAccessible()方法的说明【可用于微信支付 签名生成】...

    方法1:通过get()方法获取属性值 package com.sxd.test.controller;public class FirstCa{private Integer num;private ...

  9. virtualbox vm linux 动态获取ip

    修改动态获取ip命令: cd /etc/network/ 修改文件文件中 vi interfaces auto eth0 iface eth0 inet dhcp

最新文章

  1. 用Python更改IP地址(转)
  2. SpringMVC容器和Spring容器
  3. 设计模式 日志系统设计_模式:我们设计系统的故事
  4. Linux 命令之 apt-get -- APT 软件包管理工具
  5. python实用么_使用Python这么多年,才发现Python还有这些实用的功能和特点
  6. usb接口驱动_技术丨USB接口无法识别设备的处理方法
  7. Java中String、StringBuffer 、StringBuilder
  8. java jbutton间隔_如何通过百分比设置JButton宽度? - java
  9. Ubuntu20安装搜狗拼音输入法
  10. L2-036 网红点打卡攻略
  11. 【计科快速入门】 三、布尔逻辑和逻辑门
  12. sco的意思_HIV检测中的SCO值意义-3页word资料
  13. 8、135条最全弱电智能化综合布线常用术语
  14. mysql之行列转换
  15. android友盟错误日志,友盟崩溃日志分析三种方式
  16. R统计绘图-VPA(变差分解分析)
  17. windows live mail error message
  18. Java 编辑PPT SmartArt图形
  19. 作业调度与进程调度的区别
  20. 刹车片做E-mark认证费用大概多少?

热门文章

  1. 阅文集团换帅:程武辞任CEO职务 总裁侯晓楠接任
  2. 统计用户在各个月份的活跃(较大量数据)
  3. 解决:Hbuilder工具点击发行打包,一直报尚未完成社区身份验证,请点击链接xxxxx,项目xxx发布H5失败的错误。[Error]尚未完成社区身份验证
  4. python气象科研学习路线和常用技巧
  5. 深度学习的浪漫---普通图片自动转成卡通图片
  6. 传百度签约电信联通布局移动搜索
  7. 金仓数据库KingbaseES数据类型和oracle数据类型的映射表
  8. java 内存池_内存池技术介绍(图文并茂,非常清楚)
  9. Python : Turtle库--3.18画美国国旗
  10. harris角点检测c语言,Harris角点检测原理及实现