SpringBoot整合JSP一站式解决方案 20253694编辑
Heaven helps those who help themselves
资深码农+深耕理财=财富自由
欢迎关注
资深码农+深耕理财=财富自由
欢迎关注

SpringBoot整合JSP一站式解决方案
Created by Marydon on 2020-08-24 11:02
1.情景展示
对于习惯于全栈式开发的我们,前端获取后台的数据,jsp可以说是最好的选择。
2.原因分析
但是,由于springboot推崇的是前后端分离,不推荐使用jsp开发,所以,springboot的内置tomcat没有添加对jsp的支持。
这样,当我们在写html的时候,必须使用ajax或form表单来获取后端返回的数据(再也不能像之前那样,后台根据请求决定要转发的页面时,可以携带数据;虽然使用html也可以转发数据,但是,html是无法拿不到转发的数据的),这对于没有进行前后端分离的开发人员来说,无疑是增加了获取后台响应数据的开发时间成本。
所以,springboot整合jsp是十分有必要的,因为jsp获取数据相当简单(EL表达式、c标签库、写java代码),也不用我们配置视图解析器,tomcat会自动帮我们解析jsp(前后端已经分离的,就没有必要整合jsp啦,只需关注后台crud开发就可以了),下面讲讲如何整合jsp以及期间我所遇到的问题及解决办法。
前后端分离的本质是:将页面完全交由前端来管理,后端释放对于跳转(转发)页面的控制权(不再根据请求来决定要响应什么样的页面,只需专注根据请求返回数据即可);
这种方式有好有坏,对于项目而言,如果配有前端开发人员,建议使用前后端分离,各司其职,节约开发时间;如果没有前端开发的话,不要搞前后端分离,反正最后前端的活儿还是你来干,用jsp多省心。
3.解决方案
以maven项目为例,最重要的一点就是:添加jsp依赖。
第一步:添加对jsp的依赖
需要引入两个jar包:(不着急复制,这不一定符合你的要求)
<!-- 使用jsp引擎,springboot内置tomcat没有此依赖 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>9.0.36</version>
<!--只有编译和测试阶段生效-->
<scope>provided</scope>
</dependency>
<!--增加对 JSP 文件的支持-->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jsp-api</artifactId>
<version>9.0.36</version>
<!--只有编译和测试阶段生效-->
<scope>provided</scope>
</dependency>
对于这两个jar包定义的scope,是可变更的,按实际需求更改。
为什么加上这个标签?这个原因我们必须不得不弄得明明白白。
<scope></scope>标签,用来声明jar包的作用范围,maven的生命周期包含编译、测试、打包这三个阶段,最终,在项目部署前,我们需要对项目进行打包,maven在执行打包命令时,会先对项目进行编译和测试(其中,测试阶段可以通过命令跳过),至于为什么要讲这个,先挖个坑。
provided,应用到maven的生命周期里就是:编译和测试,换言之就是被它修饰的依赖,只有在编译和测试阶段,有效。更准确地来说,用来欺骗maven用的,因为如果编译和测试阶段没有通过的话,maven是不会执行打包命令的。
这样做,虽然通过了编译和测试阶段,在最终打包时,需要分两种情况:
情形一:打war包;
该jar包是不会被打包到项目的lib目录下,而是被放在了lib-provided当中。
情形二:打jar包。
打jar包的时候,maven照样会将provided修饰的jar包打进来。
另外,打jar包的时候,maven会自动将webapp目录排除在外(webapp下所有的文件,都不会被纳入jar包当中)。
在idea当中,程序入口xxApplication.java启动项目,本质就是:使用springboot内置的tomcat启动的;
而springboot内置tomcat不支持jsp;
spring-boot-starter-web包含spring-boot-starter-tomcat
访问一个jsp页面的请求
chrome浏览器下,会自动下载该请求的响应内容,并不会将其以html的形式展示到浏览器上(jsp会被tomcat解析成java格式的servlet)
所以说:
使用springboot内置tomcat启动项目,要想使jsp生效,必须引入jsp依赖;
另外,外置tomcat是支持jsp的:
换句话说,就是:Apache官方的tomcat的lib目录下有jsp所需的jar包;
这样一来,当我们把项目部署到外置tomcat上时,项目引入的jsp jar包和tomcat的jsp jar包就会冲突。
使用Apache官方tomcat启动项目,就不需要引入这两个jar包,引入反而是画蛇添足。
这样一来:如果引入jar包不设置作用范围,使用内置tomcat启动项目可以正常访问到jsp页面,但是,部署到外置tomcat上时,可能会引发jsp jar包冲突;
所以,我们最好设置以上两个jar包的作用范围。
设置好作用范围后,在idea当中,通过内置tomcat启动项目是可以,正常访问到jsp页面的;
如果无法访问到jsp页面,请按照下面两个步骤进行检查:
一般情况下,Include dependencies with "Provided" scope,默认是选中状态的。
意思是:在启动项目的时候,依赖这些jar包;
这样一来,即使jar包被provided限制,也不影响我们在idea当中正常使用。
但是,如果即使设置了也不生效的话,事实上,你也不可能不会生效。
下面是我之前总结的3种解决方案,在idea当中没有用的必要,这部分别看了。
方案一:使用外置tomcat启动项目。
这一点,很好理解,因为,在没有springboot前,我们都是将项目添加到tomcat中,然后启动;
所以,我们只需要将springboot的内置tomcat踢掉即可,不用添加对jsp的依赖。
使用这种方式进行开发,需要我们将springboot项目当成普通的web项目,在idea里为该项目添加tomcat,部署,启动。
方案二:注释。
在开发环境下,使用springboot启动项目,引入jsp依赖
在生产环境下(也就是部署时), 删除这两个jar包的引用或者声明为编译和测试阶段有效。
同时,还需要剔除内置tomcat的依赖。
方案三:开发环境和生产环境分离。
通过maven的profile来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | < profiles > <!--开发环境--> < profile > < id >dev</ id > <!-- 是否激活本环境 --> < activation > < activeByDefault >false</ activeByDefault > </ activation > < properties > <!--打包方式--> < project.packaging >jar</ project.packaging > <!--打包时,需要进行测试--> < skipTests >false</ skipTests > </ properties > < dependencies > <!--jsp不能够在jar中使用,只能够在War中使用 所以,如果确定部署项目的时候以jar的形式运行的话,则项目就不能使用jsp了, 因为,maven在执行打包命令时,jsp是不会被打包到jar包当中的--> <!-- 使用jsp引擎,springboot内置tomcat没有此依赖 --> < dependency > < groupId >org.apache.tomcat.embed</ groupId > < artifactId >tomcat-embed-jasper</ artifactId > < version >9.0.36</ version > </ dependency > <!--增加对 JSP 文件的支持--> < dependency > < groupId >org.apache.tomcat</ groupId > < artifactId >tomcat-jsp-api</ artifactId > < version >9.0.36</ version > </ dependency > <!-- 添加jstl标签库依赖模块 --> < dependency > < groupId >javax.servlet</ groupId > < artifactId >jstl</ artifactId > < version >1.2</ version > </ dependency > </ dependencies > </ profile > <!--生产环境--> < profile > < id >prod</ id > <!-- 默认激活本环境 --> < activation > < activeByDefault >true</ activeByDefault > </ activation > < properties > <!--如果不指定成war,默认打的将是jar包--> < project.packaging >war</ project.packaging > <!--打包时,跳过测试阶段(因为测试阶段会去连接数据库,正式数据库本地无法访问,会导致打包失败)--> < skipTests >true</ skipTests > </ properties > <!--项目中,编译和测试阶段用到的jar包,但tomcat中存在这些jar包,此时,在部署到tomcat中时,我们就需要把它们踢掉--> < dependencies > <!--内置tomcat(剔除该jar包)--> < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-tomcat</ artifactId > <!--只有编译和测试阶段生效--> < scope >provided</ scope > </ dependency > <!-- servlet依赖(只在开发时使用,因为部署到tomcat上时,tomcat有对应的jar包) --> < dependency > < groupId >javax.servlet</ groupId > < artifactId >javax.servlet-api</ artifactId > < scope >provided</ scope > </ dependency > <!-- 添加jstl标签库依赖模块 --> < dependency > < groupId >javax.servlet</ groupId > < artifactId >jstl</ artifactId > < version >1.2</ version > < scope >provided</ scope > </ dependency > </ dependencies > </ profile > </ profiles > |
profiles标签需要放在dependencies标签上面
开发环境,勾选dev;生产环境,勾选prod,然后再导包,clean,package。
我使用的是方案三。
另外,要想使用jsp,就必须将项目打包成war形式;
如果确定部署项目的时候以jar的形式运行的话,则项目就不能使用jsp了。可以在resources/template目录下使用html。(原因见文末那篇部署成功却无法访问的文章)
需要注意的是:tomcat的jsp模板引擎与高版本oracle不兼容(解决方案仔细看)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <!-- oracle --> <!--高版本的oracle jar包与jsp引擎 jar包冲突,启动会报错:找不到 ORACLE相关jar包:oraclepki.jar、osdt_core.jar、osdt_cert.jar、 ORAI18N相关jar包:orai18n-mapping.jar、orai18n-utility.jar、orai18n-collation.jar、orai18n-translation.jar、orai18n-net.jar、orai18n-servlet.jar、orai18n-lcsd.jar、orai18n-tools.jar、gdk_custom.jar tomcat-embed-jasper相关jar包:xercesImpl.jar、xml-apis.jar、serializer.jar 等之类的jar包,但并不影响项目的正常运行--> < dependency > < groupId >com.oracle.ojdbc</ groupId > < artifactId >ojdbc8</ artifactId > < version >19.3.0.0</ version > < scope >runtime</ scope > < optional >true</ optional > </ dependency > < dependency > < groupId >com.oracle.ojdbc</ groupId > < artifactId >orai18n</ artifactId > < version >19.3.0.0</ version > < scope >runtime</ scope > < optional >true</ optional > </ dependency > <!--解决方案有三种: 1.不用理会:虽然启动报错,但并不影响项目的正常运行 2.切换成低版本的ORACLE驱动:比如OJDBC6 3.去掉对jsp模板引擎的引用:tomcat-embed-jasper,但是这样,项目将无法使用jsp文件 PS:由于生产环境下,如果项目最终是要部署到tomcat上时,我们需要去除对于jsp模板引擎jar包的引用,部署到tomcat上,以上的jar包缺失的报错信息并不存在, 所以,最佳的方案是第一种--> <!--<dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.4</version> </dependency>--> <!-- json --> |
出现了类似xalan相关jar包找不到的错误,也不用管。
到这里,本文的重点也就讲完啦,基本上使用jsp就没有问题啦。下面进行controller与jsp进行交互讲解。
第二步:配置视图转发jsp所在路径
这一步可有可无,看个人喜好。
修改配置文件application.properties或者application.yml
1 2 3 4 5 6 7 8 9 10 | ####spring配置#### spring: ###控制器 mvc: ##视图 view: #响应路径前缀 prefix: /jsp/ #响应路径后缀 suffix: .jsp |
根据你的jsp实际所在位置设置路径(如果jsp放置在webapp目录下,则访问路径不用添加该目录)
第三步:创建JSP控制器
根据自己的实际需要创建controller的目录即可,这里仅供参考
配置欢迎页和404页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; /** * 项目欢迎页和404页配置 * @author: Marydon * @date: 2020年07月10日 0010 12:03 */ @Controller public class JspController { // 引用日志 private static Logger logger = LoggerFactory.getLogger(JspController. class ); /** * 首页 * @date: 2020年07月10日 0010 17:13 * @param: * @return: java.lang.String */ // 这3个请求都会进入这个方法(这两种注解方式都可以) // @RequestMapping(value = {"/","/index","/index.do"}, method = RequestMethod.GET) @GetMapping ({ "/" , "/index" , "/index.do" }) public String index() { // 跳转到欢迎页 return "index" ; } /** * 不存在的请求,跳转到404页面 * @description: ErrorConfig已经拦截了404请求,然后映射到这个请求上 * @date: 2020年07月10日 0010 17:10 * @param: * @return: java.lang.String */ @GetMapping ( "/404.do" ) public String notFound() { // 跳转到404页 return "404" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 请求转发至页面(携带响应数据)的三种方式 * 其中,第一种和第三种本质上一致 * @author: Marydon * @date: 2020年07月10日 0010 12:03 */ // 请求前缀 @RequestMapping ( "/demo" ) // 返回页面需要用这个注解 @Controller public class demoDataController { // 引用日志 private static Logger logger = LoggerFactory.getLogger(demoDataController. class ); /* * 方式一:跳转页面并响应Map数据 * @date: 2020年07月10日 0010 18:16 * @param: map * @return: java.lang.String */ @RequestMapping ( "/getMap.do" ) public String responseMap(Map<String, Object> map){ map.put( "time" , new Date()); map.put( "message" , "Map取值" ); //return 的是文件的路径+名字 // /jsp/demo/map.jsp return "demo/map" ; } /** * 方式二:返回ModelAndView * @date: 2020年07月10日 0010 18:23 * @param: * @return: org.springframework.web.servlet.ModelAndView */ @RequestMapping ( "/getModelAndView.do" ) public ModelAndView responseModelAndView(){ // 页面位置 /jsp/demo/modelAndView.jsp ModelAndView mav = new ModelAndView( "demo/modelAndView" ); mav.addObject( "time" , new Date()); mav.addObject( "message" , "ModelAndView取值" ); return mav; } /* * 方法三:直接使用Model封装内容,并返回页面字符串 * @date: 2020年07月10日 0010 18:38 * @param: model * @return: java.lang.String */ @RequestMapping ( "/getModel.do" ) public String responseModel(Model model){ // 页面位置 /jsp/demo/model.jsp model.addAttribute( "time" , new Date()); model.addAttribute( "message" , "model" ); return "demo/model" ; } /* * 返回json数据 * @decription:springmvc返回Json的两种方式 * 方式一:类添加注解@Controller,方法上添加@ResponseBody * 方式二:类上只需添加@RestController,方法上不用添加@ * 使用这种方式,对应的类就只能返回json数据,而不能转发至页面上了(前后端分离一般采用的就是这种方式) * @date: 2020年07月17日 0017 17:14 * @param: * @return: java.util.Map<java.lang.String,java.lang.Object> */ @ResponseBody @RequestMapping ( "/getJson.do" ) public Map<String, Object> responseJSON(){ Map<String, Object> map = new HashMap<>(); map.put( "data" , "Json数据" ); return map; } } |
介绍已经够详细的了,看注释就能懂。
第四步:配置响应页面并取值
1 2 3 4 5 6 7 8 9 10 11 12 | <%@ page language="java" pageEncoding="UTF-8"%> <! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> < html > < head > < meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> < title >数据交互一</ title > </ head > < body > < h1 >${message}:${time}</ h1 > </ body > </ html > |
map.jsp、model.jsp、modelAndView.jsp这三个页面的取值方式用的都是EL表达式。
4.关于整合jsp的延伸
2022年2月24日19:06:52
通常情况下,使用jsp进行前端功能开发,我们会使用c标签库,所以,需要添加jstl依赖。
查看代码
<!-- 添加jstl标签库依赖模块 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> <!--只有编译和测试阶段生效--> <scope>provided</scope> </dependency> <!-- 添加jstl标签库依赖 --> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> <!--只有编译和测试阶段生效,会被打包到lib-provided目录下--> <scope>provided</scope> </dependency>
由第一步我们知道:在idea当中,即使jar包被设置成了只在编译和测试阶段有效,idea也可以随心所欲地使用这些jar包。
基于idea的这个功能,我们不放对jar包做进一步优化:
查看代码
<!--2022年2月24日18:31:22--> <!--springboot内置tomcat--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <!--只有编译和测试阶段生效,会被打包到lib-provided目录下--> <scope>provided</scope> </dependency> <!-- 使用jsp引擎,springboot内置tomcat没有此依赖 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>9.0.36</version> <!--只有编译和测试阶段生效,会被打包到lib-provided目录下--> <!--在idea当中,即使被设置成provided,springboot在运行的时候,也会引用该jar包--> <!--(只在开发时使用,因为部署到tomcat上时,tomcat的lib目录下有对应的jar包)--> <scope>provided</scope> </dependency> <!--增加对 JSP 文件的支持--> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jsp-api</artifactId> <version>9.0.36</version> <!--只有编译和测试阶段生效,会被打包到lib-provided目录下--> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <!--只有编译和测试阶段生效,会被打包到lib-provided目录下--> <scope>provided</scope> </dependency>
因为上面提到的idea的功能,所以,我们完全可以将外置tomcat不需要的jar包全部用provided进行限定;
这样一来,也不用区分是开发环境还是生产环境了。
另,关于jstl的两个jar包的引用方式即可以使用被provided限定,也可以不限定。
查看代码
<!-- 添加jstl标签库依赖模块 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> <!--外置tomcat的lib目录下没有此jar包,如果有,可以将其从打包后的war包当中删掉--> <!--<scope>provided</scope>--> </dependency> <!-- 添加jstl标签库依赖 --> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> <!--外置tomcat的lib目录下没有此jar包,如果有,可以将其从打包后的war包当中删掉--> <!--<scope>provided</scope>--> </dependency>
如果限定的话,当tomcat的lib目录下没有这两个jar包时,我们可以将其从lib-provided目录中抽出来,放到tomcat的lib目录下或自身的lib下。
如果不限定的话,它俩将会打包到自身项目的lib目录下,当tomcat的lib下有这两个jar,且冲突的时候,我们可以将tomcat或者自身下的jar包进行移除。
2022年3月23日15:48:15
5.关于maven<scope></scope>的说明
compile:默认值,表示当前依赖包,要参与当前项目的编译,后续测试,运行时,打包;
provided:代表在编译和测试的时候用,运行,打包的时候不会打包进去;
test:表示当前依赖包只参与测试时的工作:比如Junit;
runtime:表示当前依赖包只参与运行周期,其他跳过了;
system:从参与度和provided一致,不过被依赖项不会从maven远程仓库下载,而是从本地的系统拿(需要通过systemPath属性来定义路径)。
写在最后
哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!
相关推荐:
与君共勉:最实用的自律是攒钱,最养眼的自律是健身,最健康的自律是早睡,最改变气质的自律是看书,最好的自律是经济独立 。
您的一个点赞,一句留言,一次打赏,就是博主创作的动力源泉!
↓↓↓↓↓↓写的不错,对你有帮助?赏博主一口饭吧↓↓↓↓↓↓
本文来自博客园,作者:Marydon,转载请注明原文链接:https://www.cnblogs.com/Marydon20170307/p/13529722.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
2018-08-24 java 判断String字符串是不是json数据
2017-08-24 URL中的#
2017-08-24 js实现页面跳转的两种方式