建设网站哪个公司好,巴中公司网站建设,海兴县建设工程招标信息网站,如何做一个网站代码小Hub领读#xff1a;嘿嘿#xff0c;之前我也发了一篇类似的项目#xff0c;SpringBootVue的项目#xff0c;还有视频讲解#xff0c;如果这篇文章看完不懂#xff0c;不妨去看看我的视频讲解哈#xff0c;超级详细#xff01;太赞了#xff0c;SpringBootVue前后端分…小Hub领读嘿嘿之前我也发了一篇类似的项目SpringBootVue的项目还有视频讲解如果这篇文章看完不懂不妨去看看我的视频讲解哈超级详细太赞了SpringBootVue前后端分离完整入门教程mp.weixin.qq.com作者_Yufanhttp://cnblogs.com/yfzhou/p/9813177.html本文总结自实习中对项目的重构。原先项目采用 Springbootfreemarker 模版开发过程中觉得前端逻辑写的实在恶心后端 Controller 层还必须返回 Freemarker 模版的 ModelAndView逐渐有了前后端分离的想法由于之前没有接触过主要参考的还是网上的一些博客教程等初步完成了前后端分离在此记录以备查阅。一、前后端分离思想前端从后端剥离形成一个前端工程前端只利用 Json 来和后端进行交互后端不返回页面只返回 Json 数据。前后端之间完全通过 public API 约定。二、后端 SpringbootSpringboot 就不再赘述了Controller 层返回 Json 数据。RequestMapping(value /add, method RequestMethod.POST)ResponseBodypublic JSONResult addClient(RequestBody String param) {JSONObject jsonObject JSON.parseObject(param);String task jsonObject.getString(task);ListObject list jsonObject.getJSONArray(attributes);ListString attrList new LinkedList(list);Client client JSON.parseObject(jsonObject.getJSONObject(client).toJSONString(),new TypeReferenceClient(){});clientService.addClient(client, task, attrList);return JSONResult.ok();}Post 请求使用 RequestBody 参数接收。三、前端 Vue ElementUI Vue router Vuex axios webpack主要参考https://cn.vuejs.org/v2/guide/https://github.com/PanJiaChen/vue-admin-template/blob/master/README-zh.mdhttps://github.com/PanJiaChen/vue-element-admin这里主要说一下开发工程中遇到的问题1. 跨域由于开发中前端工程使用 webpack 启了一个服务所以前后端并不在一个端口下必然涉及到跨域XMLHttpRequest 会遵守同源策略 (same-origin policy). 也即脚本只能访问相同协议 / 相同主机名 / 相同端口的资源, 如果要突破这个限制, 那就是所谓的跨域, 此时需要遵守 CORS(Cross-Origin Resource Sharing) 机制。解决跨域分两种1、server 端是自己开发的这样可以在在后端增加一个拦截器Component
public class CommonIntercepter implements HandlerInterceptor {private final Logger logger LoggerFactory.getLogger(this.getClass());Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {//允许跨域,不能放在postHandle内response.setHeader(Access-Control-Allow-Origin, *);if (request.getMethod().equals(OPTIONS)) {response.addHeader(Access-Control-Allow-Methods, GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,PATCH);response.addHeader(Access-Control-Allow-Headers, Content-Type, Accept, Authorization);}return true;}
}response.setHeader(Access-Control-Allow-Origin, *);主要就是在 Response Header 中增加 Access-Control-Allow-Origin: *if (request.getMethod().equals(OPTIONS)) {response.addHeader(Access-Control-Allow-Methods, GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,PATCH);response.addHeader(Access-Control-Allow-Headers, Content-Type, Accept, Authorization);}由于我们在前后端分离中集成了 shiro因此需要在 headers 中自定义一个Authorization字段此时普通的 GET、POST 等请求会变成 preflighted request即在 GET、POST 请求之前会预先发一个 OPTIONS 请求这个后面再说。推荐一篇博客介绍 preflighted request。https://blog.csdn.net/cc1314_/article/details/782723292、server 端不是自己开发的可以在前端加 proxyTable。不过这个只能在开发的时候用后续部署可以把前端项目作为静态资源放到后端这样就不存在跨域由于项目需要我现在是这么做的根据网上博客介绍可以使用 nginx具体怎么做可以在网上搜一下。遇到了网上很多人说的proxyTable 无论如何修改都没效果的现象。1、非常重要确保 proxyTable 配置的地址能访问因为如果不能访问在浏览器 F12 调试的时候看到的依然会是提示 404。并且注意在 F12 看到的 js 提示错误的域名是 js 写的那个域名并不是代理后的域名。l 楼主就遇到这个问题后端地址缺少了查询参数代理设置为后端地址然而 F12 看到的错误依然还是本地的域名并不是代理后的域名2、就是要手动再执行一次 npm run dev四、前后端分离项目中集成 shiro可以参考http://blog.csdn.net/u013615903/article/details/78781166这里说一下实际开发集成过程中遇到的问题1、OPTIONS 请求不带Authorization请求头字段前后端分离项目中由于跨域会导致复杂请求即会发送 preflighted request这样会导致在 GETPOST 等请求之前会先发一个 OPTIONS 请求但 OPTIONS 请求并不带 shiro 的Authorization字段shiro 的 Session即 OPTIONS 请求不能通过 shiro 验证会返回未认证的信息。解决方法给 shiro 增加一个过滤器过滤 OPTIONS 请求public class CORSAuthenticationFilter extends FormAuthenticationFilter {private static final Logger logger LoggerFactory.getLogger(CORSAuthenticationFilter.class);public CORSAuthenticationFilter() {super();}Overridepublic boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {//Always return true if the requests method is OPTIONSif (request instanceof HttpServletRequest) {if (((HttpServletRequest) request).getMethod().toUpperCase().equals(OPTIONS)) {return true;}}
return super.isAccessAllowed(request, response, mappedValue);}Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {HttpServletResponse res (HttpServletResponse)response;res.setHeader(Access-Control-Allow-Origin, *);res.setStatus(HttpServletResponse.SC_OK);res.setCharacterEncoding(UTF-8);PrintWriter writer res.getWriter();MapString, Object map new HashMap();map.put(code, 702);map.put(msg, 未登录);writer.write(JSON.toJSONString(map));writer.close();return false;}
}贴一下我的 config 文件Configuration
public class ShiroConfig {Beanpublic Realm realm() {return new DDRealm();}Beanpublic CacheManager cacheManager() {return new MemoryConstrainedCacheManager();}/*** cookie对象;* rememberMeCookie()方法是设置Cookie的生成模版比如cookie的namecookie的有效时间等等。* return*/Beanpublic SimpleCookie rememberMeCookie(){//System.out.println(ShiroConfiguration.rememberMeCookie());//这个参数是cookie的名称对应前端的checkbox的name rememberMeSimpleCookie simpleCookie new SimpleCookie(rememberMe);//!-- 记住我cookie生效时间30天 ,单位秒;--simpleCookie.setMaxAge(259200);return simpleCookie;}/*** cookie管理对象;* rememberMeManager()方法是生成rememberMe管理器而且要将这个rememberMe管理器设置到securityManager中* return*/Beanpublic CookieRememberMeManager rememberMeManager(){//System.out.println(ShiroConfiguration.rememberMeManager());CookieRememberMeManager cookieRememberMeManager new CookieRememberMeManager();cookieRememberMeManager.setCookie(rememberMeCookie());//rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)cookieRememberMeManager.setCipherKey(Base64.decode(2AvVhdsgUs0FSA3SDFAdag));return cookieRememberMeManager;}Beanpublic SecurityManager securityManager() {DefaultWebSecurityManager sm new DefaultWebSecurityManager();sm.setRealm(realm());sm.setCacheManager(cacheManager());//注入记住我管理器sm.setRememberMeManager(rememberMeManager());//注入自定义sessionManagersm.setSessionManager(sessionManager());return sm;}//自定义sessionManagerBeanpublic SessionManager sessionManager() {return new CustomSessionManager();}public CORSAuthenticationFilter corsAuthenticationFilter(){return new CORSAuthenticationFilter();}Bean(name shiroFilter)public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager) {ShiroFilterFactoryBean shiroFilter new ShiroFilterFactoryBean();shiroFilter.setSecurityManager(securityManager);//SecurityUtils.setSecurityManager(securityManager);MapString, String filterChainDefinitionMap new LinkedHashMap();//配置不会被拦截的链接顺序判断filterChainDefinitionMap.put(/, anon);filterChainDefinitionMap.put(/static/js/**, anon);filterChainDefinitionMap.put(/static/css/**, anon);filterChainDefinitionMap.put(/static/fonts/**, anon);filterChainDefinitionMap.put(/login/**, anon);filterChainDefinitionMap.put(/corp/call_back/receive, anon);//authc:所有url必须通过认证才能访问anon:所有url都可以匿名访问filterChainDefinitionMap.put(/**, corsAuthenticationFilter);shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);//自定义过滤器MapString, Filter filterMap new LinkedHashMap();filterMap.put(corsAuthenticationFilter, corsAuthenticationFilter());shiroFilter.setFilters(filterMap);return shiroFilter;}/*** Shiro生命周期处理器 * return*/Beanpublic LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** 开启Shiro的注解(如RequiresRoles,RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能 * return*/BeanDependsOn({lifecycleBeanPostProcessor})public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator new DefaultAdvisorAutoProxyCreator();advisorAutoProxyCreator.setProxyTargetClass(true);return advisorAutoProxyCreator;}Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}
}2、设置 session 失效时间shiro session 默认失效时间是 30min我们在自定义的 sessionManager 的构造函数中设置失效时间为其他值public class CustomSessionManager extends DefaultWebSessionManager {private static final Logger logger LoggerFactory.getLogger(CustomSessionManager.class);private static final String AUTHORIZATION Authorization;private static final String REFERENCED_SESSION_ID_SOURCE Stateless request;public CustomSessionManager() {super();setGlobalSessionTimeout(DEFAULT_GLOBAL_SESSION_TIMEOUT * 48);}Overrideprotected Serializable getSessionId(ServletRequest request, ServletResponse response) {String sessionId WebUtils.toHttp(request).getHeader(AUTHORIZATION);//如果请求头中有 Authorization 则其值为sessionIdif (!StringUtils.isEmpty(sessionId)) {request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);return sessionId;} else {//否则按默认规则从cookie取sessionIdreturn super.getSessionId(request, response);}}
}五、部署项目前端项目部署主要分两种方法**1、将前端项目打包npm run build成静态资源文件放入后端一起打包。**后端写一个 Controller 返回前端界面我使用 Vue 开发的是单页面应用但是这样其实又将前后端耦合在一起了不过起码做到前后端分离开发方便开发的目的已经达成也初步达成了要求由于项目的需要我是这样做的并且免去了跨域问题。RequestMapping(value {/, /index}, method RequestMethod.GET)public String index() {return /index;}2. 将前端工程另启一个服务tomcatnginxnodejs这样有跨域的问题。说一下我遇到的问题1、nginx 反向代理导致当访问无权限的页面时shiro 302 到 unauth 的 controller访问的地址是 https重定向地址是 http导致了无法访问。不使用 shiro 的 shiroFilter.setLoginUrl(/unauth);当页面无权限访问时我们在过滤器里直接返回错误信息不利用 shiro 自带的跳转。看过滤器中的 onAccessDenied 函数public class CORSAuthenticationFilter extends FormAuthenticationFilter {private static final Logger logger LoggerFactory.getLogger(CORSAuthenticationFilter.class);public CORSAuthenticationFilter() {super();}Overridepublic boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {//Always return true if the requests method is OPTIONSif (request instanceof HttpServletRequest) {if (((HttpServletRequest) request).getMethod().toUpperCase().equals(OPTIONS)) {return true;}}return super.isAccessAllowed(request, response, mappedValue);}Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {HttpServletResponse res (HttpServletResponse)response;res.setHeader(Access-Control-Allow-Origin, *);res.setStatus(HttpServletResponse.SC_OK);res.setCharacterEncoding(UTF-8);PrintWriter writer res.getWriter();MapString, Object map new HashMap();map.put(code, 702);map.put(msg, 未登录);writer.write(JSON.toJSONString(map));writer.close();return false;}
}先记录这么多有不对的地方欢迎指出推荐阅读太赞了SpringBootVue前后端分离完整入门教程分享一套SpringBoot开发博客系统源码以及完整开发文档速度保存Github上最值得学习的100个Java开源项目涵盖各种技术栈2020年最新的常问企业面试题大全以及答案