vue+shiro+springboot项目整合部署到linux tomcat8.5

15 篇文章 2 订阅
3 篇文章 0 订阅

事情的起因:这几天在做一个项目的整合部署, 中间遇到了很多的坑, 现在记录一下遇到的问题, 以及解决方案

一 vue项目打包

vue项目是前端独立的, 在部署时需要将vue项目打包, 生成的文件放入到后台系统的静态资源路径下, 一般是static文件夹

1.1 注释掉独立开发时配置的url前缀

这里需要注意, 在打包前需要将项目中明确指出ip的位置注释掉, 在打包后的项目文件就是一个纯静态文件了, 不再是一个独立的系统了, 将其打包生成的文件放入后台静态资源static路径下, 他将与后台系统共用同一个ip和端口, 也不涉及到跨域问题了, 所以这里需要将异步请求url设置的请求前缀给注释掉.
如果使用了vue-upload插件的, 在页面配置中设置了target, 这里也指定了ip和端口号, 需要去掉ip和端口, 只留下后面的请求地址**
在这里插入图片描述

1.2 查找项目的build命令

在vue项目的package.json文件中, 可以找到scripts配置选项
在这里插入图片描述
这里的build:prod就是打包需要执行的命令

具体命令为

npm run build:prod

1.3 将打包后生成的文件放入springboot的静态资源文件夹中

执行完项目的打包命令之后, 会在项目的根目录下生成一个dist的文件夹, 这里面就是打包生成的文件, 将里面的文件全部拷贝到后台系统的静态资源路径static下, 正常打包之后只会生成一个static文件夹和一个index.html文件, 我这里的titleIcon.png是我项目中的一个图片, 放在了根目录,所以这里打包之后生成了这个文件, 那么就需要将这三个都拷贝到后台static中
在这里插入图片描述
后台项目中使用的springboot框架, 这个框架我在网上看到一些资料说是需要使用tomcat8以上版本, 然后tomcat需要依赖的jdk版本,要高于或等于tomcat版本, 我没有自己考证过, 但是现在安装常见的jdk8 和 tomcat8.5 就可以了, 没有什么问题

将打包后的文件放入static中, 注意前端打包生成的dist文件夹中也包含一个static文件, 这里面是前端的静态文件, 可以打开看一下, 一般就是一些js, css文件,图片等, 而后台系统中的static文件夹是后台默认搜索的资源文件夹, 这里两个static不要混淆, 打包后的文件放入后台系统之后目录结构是这样的
在这里插入图片描述
这三个是前端的打包文件, 上一层的static文件夹是springboot的静态文件夹, 千万别弄混了!
在后台的shiro框架中, 我们需要设置放行哪些url, 如果不设置, shiro是六亲不认 铁面无私的, 谁也别想溜过去, 首先应该将静态文件夹放行, 也就是static文件夹(注意这里是static下的statis文件夹)

二 shiro白名单配置

	// Filter工厂,设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> map = new LinkedHashMap<>();

        // 登出
        map.put("/user/logout", "anon");
        // 登录
        map.put("/user/login", "anon");
        // 根目录访问,返回index
        map.put("/", "anon");
        // 静态资源
        map.put("/static/**", "anon");
        // 登录首页放行
        map.put("/index.html", "anon");
        // 对所有用户认证
        map.put("/**", "authc");
        // 登录
        shiroFilterFactoryBean.setLoginUrl("/user/login");
        // 成功后首页
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 鉴权页面,认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        // 自定义过滤器
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        filterMap.put("corsAuthenticationFilter", corsAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
        return shiroFilterFactoryBean;
    }

这里逐个进行解释

2.1 登录请求

登录方法就不解释了, 登录请求在发送请求时, 当前shiro肯定是没有token的了, 所以必须要给一个特权, 过去吧~ 过去吧~

2.2 登出请求

2.2.1 有人会有疑问了, 为啥登出请求也要特权呢?

原因在于前台, 当前台发送一个请求, shiro检测到当前用户状态未登录或登录超时时, 就会根据setLoginUrl方法设置的值去跳转到/user/login的请求地址中, 这是登录验证的请求, 可以验证当前用户的用户名密码是否正确等等一系列操作, 当然这里面也有一系列的异常拦截, 其中就包括这个"未登录"的拦截, 当用户未登录时, 就会返回前台一个json串, 告诉前台你当前未登录, 这时前端就会控制着进行一系列的退出操作,store数据清空, cookies清空, 发送请求到后台退出登录, 最后跳转到登录页, 这里发送请求到后台时, 自然就需要放行了, 还有一点需要说明就是这里的退出操作不一定是由后台检测到登录超时控制的, 有可能是前端主动点击了退出登录按钮, 这里是将退出登录方法共用了, 所以不管什么情况造成的退出登录, 都需要发送请求到后台

2.2.2 setLoginUrl为何设置返回一个json串

那么又有同学会问了, 为啥setLoginUrl不直接设置跳转一个登录页面呢? 为啥要返回一个json串, 让前台去处理未登录呢?
这里就涉及到vue的前端独立了, 因为vue在前端独立开发时, 他的页面跳转是由前端路由控制的, 在开发的时候是这样, 与后台整合到一起之后还是应该由前端来控制路由跳转, 如果整合之后由后台控制跳转了, 那代码不就需要重写了嘛
还有一点,前端独立开发时, 在前端浏览器中也记录着相应的store数据和cookies数据, 前端的路由跳转都是依据前台的cookies进行跳转的, 如果后台检测到登录超时, 他返回了一个页面, 那么也只能返回index.html页面, 这个页面就是一个启动页, 还是会调用路由中的首页, 这个首页会检测是否有cookies, 如果有, 还是会跳转到系统内, 并不会跳到登录页, 所以必须要返回一个json, 让前端把相应的store和cookies处理好,才能正确的跳转到登录页

2.3 根路径跳转

上面说了setLoginUrl里设置返回的是一个json串, 不是一个页面, 那么如何访问首页呢?
这里配置了根目录"/“可以放行的访问,在loginController中有一个方法, 用以处理根路径请求的控制, 返回值就是一个index字符串, 什么意思呢?就是当访问localhost:8080时, 会自动跳转到index.html文件中去启动首页,结合一下上面介绍登出方法时说的内容, setLoginUrl中设置的请求地址url只能返回一个json串, 它来控制返回的数据, 如果是已登录状态, 那么需要返回相应的请求结果数据, 如果是未登录状态, 就需要返回一个json告诉前台当前登录超时或未登录, 前端进行相应的处理,然后跳到登录页, 这里对根路径放行, 其实就是给项目设置了一个入口, 当然我们希望url地址越简洁越好, 所以就设置了”/"

2.4 静态文件放行

静态文件就是springboot项目中static下的文件, 包括static下的static文件夹和index.html还有我的那个titleIcon.png文件, 我这里没有对这个titleIcon.png放行,但是却可以正常显示图片, 有点不解为什么,
之前在上面介绍了访问根路径可以返回一个index字符串, springboot会自动找到index.html文件, 这时就会又发起一个请求index.html的url, 如果这里不放行index.html的话, 那就没办法访问首页了, 也就是说, 项目的入口被shiro拦住了!这个问题也是自己苦思良久才想明白的, 之前这个问题卡了我好几天时间, 一直找不好setLoginUrl应该配置的数据, 如果返回json, 那项目就没有入口了, 访问的时候 就会返回一个未登录的json到浏览器, 如果写一个返回页面index的字符串, 那登录超时就不会有相应的跳回登录页的控制, 感觉有点不可兼得了, 后来仔细想了一下shiro拦截的先后逻辑顺序, 终于捋清楚了!

2.5 url拦截验证

后面的"/**“设置为”authc"就是对剩余的所有请求都进行验证, 开启了六亲不认模式, 没有令牌说啥也不好使, 就是天王老子来了那也不行!

三 springboot打war包部署

接下来就需要打包了, 这里使用maven工具打包, 每一个开发工具都可以集成maven, 都有快捷键的, 如何打包就不介绍了, 根据自己的开发工具上网查一下如何打包就行了

3.1 找不到mybatis的接口方法

遇到一个问题就是springboot打包, 部署到tomcat之后报错说是找不到mybatis中的xml接口方法, 我就很诧异了, 为啥使用IDE的时候就能正常启动, 打包之后放在tomcat上就报错了呢?后来查了一下资料, 发现自己的xml文件没有放在springboot的resources文件夹下, 这时候资源文件扫描不到他, 我的xml文件为了开发方便, 与Mapper接口文件放在了同一个目录下, 也就是java路径下, 这时候就需要在maven的pom.xml文件中配置扫描路径了, 把这个路径加载进去, 让maven打包的时候扫描到他, 就可以了

<build>
	<!-- 当 mybatis的xml文件不在resource下时, maven打包不会找到xml文件, 这是需要通过如下配置指定打包时需要扫描的source文件位置 -->
	<resources>
        <resource>
			<directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
        <resource>
        	<directory>src/main/resources</directory>
        </resource>
    </resources>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
	<finalName>demo</finalName>
</build>

在application-dev.yml中需要配置扫描路径

mybatis:
  mapper-locations: classpath:com/demo/mapper/*/*Mapper.xml

配置完之后就清清爽爽了

3.2 打包部署到linux服务器的tomcat上面

打包之后放在本地window的tomcat下运行一下没有问题, 然后美滋滋的拿到linux上去运行, 居然报错?
我就很差异了, 为啥呢?
先把报错信息贴出来

10-May-2020 14:15:24.490 INFO [localhost-startStop-1] org.apache.catalina.startup.ExpandWar.expand An expanded directory [/soft/path/tomcat-8.5.50/webapps/xadPwdManage] was found with a last modified time that did not match the associated WAR. It will be deleted.
10-May-2020 14:15:49.929 SEVERE [localhost-startStop-1] 
org.apache.catalina.core.ContainerBase.addChildInternal ContainerBase.addChild: start: 
	org.apache.catalina.LifecycleException: Failed to start component 
	[StandardEngine[Catalina].StandardHost[localhost].StandardContext[/demo]]
		at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:198)
		at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:743)
		at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:719)
		at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705)
		at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:970)
		at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1841)
		at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
		at java.util.concurrent.FutureTask.run(FutureTask.java:266)
		at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
		at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
		at java.lang.Thread.run(Thread.java:748)
	Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
		at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105)
		at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
		at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
		at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
		at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
		at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
		at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
		at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:157)
		at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:137)
		at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:91)
		at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:171)
		at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5154)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
		... 10 more
	Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
		at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:402)
		at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377)
		at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774)
		... 29 more
	Caused by: org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
		at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:115)
		at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
		at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
		at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
		at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:69)
		at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.jdbcStatement(GenerationTargetToDatabase.java:77)
		at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:53)
		at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlString(SchemaDropperImpl.java:375)
		at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlStrings(SchemaDropperImpl.java:359)
		at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:241)
		at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:154)
		at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:126)
		at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
		at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:144)
		at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)
		at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)
		at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)
		at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939)
		at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
		at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
		at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
		... 33 more
	Caused by: org.postgresql.util.PSQLException: The connection attempt failed.
		at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:292)
		at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49)
		at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:195)
		at org.postgresql.Driver.makeConnection(Driver.java:454)
		at org.postgresql.Driver.connect(Driver.java:256)
		at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:136)
		at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:369)
		at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:198)
		at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:467)
		at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:541)
		at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115)
		at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
		at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
		at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180)
		at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:43)
		... 49 more
	Caused by: java.net.SocketTimeoutException: connect timed out
		at java.net.PlainSocketImpl.socketConnect(Native Method)
		at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
		at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
		at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
		at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
		at java.net.Socket.connect(Socket.java:606)
		at org.postgresql.core.PGStream.<init>(PGStream.java:70)
		at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:91)
		at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:192)
		... 63 more

这里有用的只有这一句话

org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/demo]]

这里需要先说明一下,由于本地开发, 所以我的数据库是安装在我本地window上的
网上又是查了好几天的解决方案, 有的说是缺少jar包, maven在打包的时候, 有报错,部分jar包没有打包成功, 我看了一下我这里报错信息没有提示有jar打包失败,然后就在技术群里问大家, 看看有没有谁遇到过类似的,他们说ping一下本地window的ip, 这里可以ping通, 但是就是报错 还带着一个localhost字样, 就让我很纠结,后来一个人说是不是防火墙的问题,我就把防火墙关闭了…然后启动…就可以访问了…
这个问题呢, 其实原因比较简单, 后来想了一下, 无非就是在其他linux服务器上面访问本机的数据库, 没有开放端口, 后来我试了一下, 把防火墙还是正常开启, 然后开放一下数据库的端口号, 能不能访问呢? 答案是可以的, 那么这样就安全了很多嘛
项目可以正常在linux上启动, 又是没有bug的一天了 美滋滋

3.3 设置tomcat访问时不加项目名称

但是 别高兴的太早, 这里在访问的时候, tomcat访问需要在url上面加上项目名, 这就有点不美丽了, 其实加上了也没事, 多一层地址影响不大, 但是后来进入项目中发现, 一些个异步请求开始404了, 我一看控制台的请求地址, 发现那是五花八门啊,我的项目名是demo
登录地址是正常的

192.168....:8080/demo/user/login

第一个404地址是

192.168....:8080/abc/abc

正常应该在8080后面有一层demo的啊, 哪去了???
第二个404地址是

192.168....:8080/abc

这下直接丢了两层???
WTF???
然后我就想到了百度一下tomcat访问不加项目名
果然可以解决
在tomcat根目录下, 打开conf/server.xml文件
在Host标签里 添加一条内容

 <Context docBase="demo" path="/" reloadable="true" crossContext="true"/>

docBase设置的项目名, path就是访问的地址
那么这里是不是可以设置多个Context标签, 让多个项目运行在同一个tomcat下呢? 前提是使用同一个端口哦???你可以自己验证一下 , 我还没有试过
这时候我们访问192.168…:8080就可以直接进入到项目的登录页了, 登录超时也是可以正常返回, 然后跳转登录页的了 这下真的是没有bug的一天了!!! 美滋滋

至此, 问题完美解决!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值