I. VUE project development plan

Using the vue official scaffolding to create separate the front end of the project, to do and the back-end completely independent development and deployment, the back-end separately deployed a purely restful services, and front end direct use nginx to deploy, this is called the before and after the end of the complete separation architecture development pattern, but there are a lot of API access in the separation problem need to solve, Including deployed Vue Router routing requires configuring the rewrite rules in nginx. This completely separated architecture is also adopted by Internet companies at present. The back-end server no longer needs to handle static resources, which can also reduce some pressure on the back-end server.

Second, why do the front and back end separation development merge

In traditional industries, many projects are driven by project ideas rather than products, and a project is sold to many customers and deployed to their local computer rooms. In some traditional industries, the technology of deployment and implementation personnel cannot compare with the operation and maintenance team of Internet companies, and automatic construction and container deployment cannot be achieved due to various variable environments. Therefore, in this case, the deployment of service software requirements should be minimized, and the number of packages should be minimized. In view of this situation, the use of independent development in the development of the front and back end, the whole development method and the vUE project development scheme mentioned above is the same, but the back-end Springboot package release will be the front-end build output into together, and finally only need to deploy the Springboot project, no need to install the Nginx server.

Key operations of springboot and VUE integration

In fact, in this paper, the front-end development is separated. After the front-end development, the files and index.html in dist static built by build are directly copied to Springboot resource/static. The following is an example diagram:

Vue front-end Project:

Springboot projects:

 

 

This is the simplest way to merge, but if it is an engineering level project development, it is not recommended to use manual merge, and it is not recommended to build the front-end code and submit it to SpringBoot resouce. The best way is to keep the front-end and back-end completely independent development code, and the project code does not affect each other. With the help of Jenkins’ construction tools, the front-end construction is triggered when springboot is built, and automatic scripts are written to copy the resources built by the front-end Webpack to Springboot and then package the JAR. Finally, a Springboot project completely includes the front and back ends.

Fourth, the integration of the core issues

After the above integration, there are two major problems:

1. Static resources cannot be accessed.

2. The path of the vue router cannot be resolved.

To solve the first problem, we must respecify springBoot’s static resource handling prefix:

@Configuration
public class SpringWebMvcConfig extends WebMvcConfigurerAdapter {
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    super.addResourceHandlers(registry); }}Copy the code

Rewrite the router (vue) over the routing path (vue) instead of springBoot (springBoot). Then write filters in SpringBoot to intercept specific suffixes to do routing processing of requests to vUE. Such as:

const router = new VueRouter({
 mode: 'history',
 base: __dirname,
 routes: [
  {
   path: '/ui/first.vhtml',
   component: First
  },
  {
   path: '/ui/second.vhtml',
   component: secondcomponent
  }
 ]
})
Copy the code

It is perfectly possible to write the back end filter and then package it, but front-end development of direct access to the suffixed path is problematic.

The other way is to give the front-end route path a uniform prefix such as/UI. In this case, the back-end write filter matches the prefix and does not affect the front-end development of route resolution problems. Filter reference is as follows:

/**
 * be used to rewrite vue router
 *
 * @author yu on 2017-11-22 19:47:23.
 */
public class RewriteFilter implements Filter {
  /** * rewrite to the target address */
  public static final String REWRITE_TO = "rewriteUrl";
  /** * Intercepted URL. Url wildcards are separated by semicolons (;)
  public static final String REWRITE_PATTERNS = "urlPatterns";
  private Set<String> urlPatterns = null;// Configure the URL wildcard
  private String rewriteTo = null;
  @Override
  public void init(FilterConfig cfg) throws ServletException {
    // Initialize the interception configuration
    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();
    // The matched path is overwritten
    if (isMatches(urlPatterns, servletPath)) {
      req.getRequestDispatcher(context+"/"+rewriteTo).forward(req, resp);
    }else{ chain.doFilter(req, resp); }}@Override
  public void destroy(a) {}/** * Returns true if matched, false if not@paramPatterns Regular expressions or wildcards *@paramUrl Indicates the requested URL *@return* /
  private boolean isMatches(Set<String> 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; }}Copy the code

Filter registration:

@SpringBootApplication
public class SpringBootMainApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringBootMainApplication.class, args);
  }
  @Bean
  public EmbeddedServletContainerCustomizer containerCustomizer(a) {
    return (container -> {
        ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/errors/401.html");
        ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/errors/404.html");
        ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/errors/500.html");
        container.addErrorPages(error401Page, error404Page, error500Page);
    });
  }
  @Bean
  public FilterRegistrationBean testFilterRegistration(a) {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new RewriteFilter());// Register the rewrite filter
    registration.addUrlPatterns("/ *");
    registration.addInitParameter(RewriteFilter.REWRITE_TO,"/index.html");
    registration.addInitParameter(RewriteFilter.REWRITE_PATTERNS, "/ui/*");
    registration.setName("rewriteFilter");
    registration.setOrder(1);
    returnregistration; }}Copy the code

Springboot then hands the front-end routing resources to the routing source. At this point, the whole complete front and back end separation development merge scheme is completed. This approach also makes it easy to completely separate the front and back end of the development deployment when conditions are available later.