在软件开发界,前后端分离的架构模式广受青睐。正如文中所述,采用vue构建前端,后端则采用纯服务架构,这种前后端分离的部署方式已成为主流开发趋势。然而,在这个过程中,API权限管理和路由配置等环节却常常成为困扰开发者的问题。
前后端分离架构的优势
现代互联网公司普遍使用前后端分离的设计。这种架构使得后端能够专注于处理业务逻辑,比如在大型电商项目中,后端专门负责订单处理和库存管理等繁复业务。同时,后端不再负责静态资源,这大大减轻了服务器的负担。例如,某知名电商网站采用这种架构后,服务器的响应速度提升了20%。此外,前端可以独立更新页面效果,从而提升了开发效率。像一些社交网站,就能快速更新界面UI,吸引更多用户。
传统行业项目开发特点
传统行业通常以项目为核心。企业开发项目,目的在于销售给众多客户并在本地机房部署,这与互联网企业做法不同。比如,在传统制造业中,信息化系统项目在开发阶段就需要根据不同客户的需求进行定制。然而,传统行业的部署实施人员技术能力有限,无法与互联网运维团队的专业水平相比。他们需应对各种环境,难以实现自动构建和容器化部署。因此,在部署时,他们有特殊要求,力求减少服务软件需求,降低包的数量。
改进后的前后端分离开发
文中所述的开发模式是在前端独立制作后,将成果打包发布时融入前端构建的输出。这种方式与传统的Vue项目开发有着相似之处。例如,在小型项目开发过程中,我们可以轻松地将前端构建下的文件和index.html直接复制到指定位置。然而,在大型工程项目中,仅靠手工合并或提交前端代码是不可行的,必须借助构建工具,启动前端构建,并编写自动化脚本,复制资源并完成打包。这就像是一条生产线上的不同环节,只有有序协作,才能生产出合格的产品。
整合后的两大问题
整合后出现了严重问题。首先,静态资源处理的前缀必须重新设定,这一点至关重要,因为它直接影响到资源分配的准确性。比如,在多媒体资源众多的项目中,若处理不当,就可能引发资源加载失败。此外,还有一个问题是vue路由路径的处理,这关系到请求的转发和正常解析。若处理不当,就如同交通系统中的道路规划混乱,导致车辆无法顺利抵达目的地。
@Configuration
public class SpringWebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
super.addResourceHandlers(registry);
}
}
问题的解决办法
静态资源处理的前缀问题,我们可以通过代码进行重新设置。至于路由路径的问题,则可以交由专门的程序来处理。有多种处理方法可供选择,比如给前端的路由path添加统一的前缀,例如“/ui”,接着在后端编写过滤器进行匹配。这样做既不会干扰前端在独立开发时的路由解析,又能让后端拦截并处理匹配到的请求。然而,直接访问带有后缀的路径可能会出现一些问题,因此在实施时需要谨慎考虑。
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [
{
path: '/ui/first.vhtml',
component: First
},
{
path: '/ui/second.vhtml',
component: secondcomponent
}
]
})
方案的后续意义
这种方案对于解决两个问题极为重要。若后期条件允许,我们便能轻松重返完全分离的开发部署模式。这就像一栋可拆装的组合屋,当需要联合时,它便能融合成一个整体,承载更多功能;而当需要独立时,又能迅速拆分,各自发展。这样的设计为项目的灵活成长带来了更多可能。
在项目开发过程中,你是否遇到过前后端协调上的难题?不妨在评论区分享你的看法。同时,也欢迎你为这篇文章点个赞,并把它分享出去。
/**
* be used to rewrite vue router
*
* @author yu on 2017-11-22 19:47:23.
*/
public class RewriteFilter implements Filter {
/**
* 需要rewrite到的目的地址
*/
public static final String REWRITE_TO = "rewriteUrl";
/**
* 拦截的url,url通配符之前用英文分号隔开
*/
public static final String REWRITE_PATTERNS = "urlPatterns";
private Set urlPatterns = null;//配置url通配符
private String rewriteTo = null;
@Override
public void init(FilterConfig cfg) throws ServletException {
//初始化拦截配置
rewriteTo = cfg.getInitParameter(REWRITE_TO);
String exceptUrlString = cfg.getInitParameter(REWRITE_PATTERNS);
if (StringUtil.isNotEmpty(exceptUrlString)) {
urlPatterns = Collections.unmodifiableSet(
new HashSet(Arrays.asList(exceptUrlString.split(";", 0))));
} else {
urlPatterns = Collections.emptySet();
}
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
String servletPath = request.getServletPath();
String context = request.getContextPath();
//匹配的路径重写
if (isMatches(urlPatterns, servletPath)) {
req.getRequestDispatcher(context+"/"+rewriteTo).forward(req, resp);
}else{
chain.doFilter(req, resp);
}
}
@Override
public void destroy() {
}
/**
* 匹配返回true,不匹配返回false
* @param patterns 正则表达式或通配符
* @param url 请求的url
* @return
*/
private boolean isMatches(Set patterns, String url) {
if(null == patterns){
return false;
}
for (String str : patterns) {
if (str.endsWith("/*")) {
String name = str.substring(0, str.length() - 2);
if (url.contains(name)) {
return true;
}
} else {
Pattern pattern = Pattern.compile(str);
if (pattern.matcher(url).matches()) {
return true;
}
}
}
return false;
}
}