5

Somewhat based on this guide:

https://jaxlondon.com/blog/java-core-languages/put-spring-boot-und-vue-js-practical-use-project-tutorial/

I have created a multi module maven project where one submodule is my backend and another submodule is my frontend. When I build the whole project first the frontend is "build" then its dist/ resources are copied to the backend which is then build and I can successfully start my spring boot backend with java -jar target/backend-1.0.0-SNAPSHOT and access it on localhost:8080

enter image description here

which makes sense based on the controller I have implemented in the backend:

@RestController
public class GreetingController {

  private static final String template = "Hello, %s!";
  private final AtomicLong counter = new AtomicLong();

  @RequestMapping("/greeting")
  public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
    return new Greeting(counter.incrementAndGet(), String.format(template, name));
  }

  @RequestMapping("/")
  public Greeting root(@RequestParam(value = "name", defaultValue = "Root!") String name) {
    return new Greeting(counter.incrementAndGet(), String.format(template, name));
  }
}

If I instead access: http://localhost:8080/index.html I end up in my frontend:

enter image description here

Which currently have the following two routes:

router.js

Vue.use(Router);

const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [
        {
            path: '/',
            name: 'home',
            component: HomeRoute
        },
        {
            path: '/myroute',
            name: 'myroute',
            component: MyRoute
        }
    ]
});

export default router;

And in e.g. App.vue I have:

<template>
<div class="hello">
    <li>
      <router-link to="/MyRoute">GoToMyRoute</router-link>
    </li>
    <li>
      <router-link to="/">GoToHome</router-link>
    </li>
    <router-view></router-view>
</div>
</template>

That I can also access, e.g.:

enter image description here

So far so good. But if I try to enter:http://localhost:8080/MyRoute directly in my browser I get:

enter image description here

which I assume is because I am missing a backend @RequestMapping for /MyRoute in my controller.

Based on the above my questions become:

  1. Do I need to maintain a backend RequestMapping for each vuejs route I have if I want to be able to access it directly in the browser?
  2. How do I separate/order my frontend and backend endpoint? Right now it seems there is no convention for when a backend endpoint is accessed compared to a pure frontend endpoint/route.
u123
  • 15,603
  • 58
  • 186
  • 303
  • I'm not very good with `Vue` but I assume that in the first situation it use URL rewrite without actual requesting of `MyRout` endpoint. But if you try to put this URL directly into the browser you got this error. Not sure which way is the most proper to resolve that. I think all component names should be routed to `index.html`. – Alexey Usharovski Dec 11 '19 at 16:17

3 Answers3

4

I would suggest you to do it this way:

  1. Have one "ui" controller on your backend which would forward any unmapped routes to your frontend application e.g.:

    @RequestMapping(value = "/**/{[path:[^\\.]*}")
    public String redirect() {
        // Forward to home page so that route is preserved.
        return "forward:/";
    }
    
  2. Other rest endpoints defined in your backend should be defined after some prefix like "/api", or "/rest" (e.g. localhost:8080/api/some-data would return your json data). So every data endpoint will have this prefix.
  3. Every route visible to user (view navigation) should be done on vue.js side as SPA routing. (e.g. localhost:8080/welcome etc.)
Guts
  • 748
  • 4
  • 10
  • Not really sure whats the point with bullet 1 you describe. If I add that I just get "forward:/" in my browser instead of that "Whitelabel Error Page" when I try to access "http://localhost:8080/MyRoute" directly in my browser . But maybe thats the point - to print some meaningful error message instead of the generic Whitelabel message? – u123 Dec 12 '19 at 16:31
  • In spring you need to route every path that is not api to vue. In vue you handle each route e.g. route to your custom 404 page etc. – Guts Dec 12 '19 at 16:40
1

I tried with the following code (inspired by Gus answer):

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;


@RestController
public class RouterCtrl {
    @RequestMapping("/**/{path:[^.]*}")
    public ModelAndView redirect() {
        return new ModelAndView("forward:/");
    }
}

And consider:

  1. Your backend endpoints must start with the prefix api/ (or some other distinctive word)

  2. Deal with the 404 not found with Router Vue, something like this:

    Vue.use(Router);
    
    const router = new Router({
        mode: 'history',
        base: process.env.BASE_URL,
        routes: [
            {
                path: '/',
                name: 'home',
                component: HomeRoute
            },
            {
                path: '/myroute',
                name: 'myroute',
                component: MyRoute
            },
            {
                path: '/:catchAll(.*)',
                name: 'notFound',
                component: NotFound
            }
        ]
    });
    
    export default router;
    

I made a simple gif to ilustrate :9

0

I would suggest remove the following from your code:

@RequestMapping("/")
  public Greeting root(@RequestParam(value = "name", defaultValue = "Root!") String name) {
    return new Greeting(counter.incrementAndGet(), String.format(template, name));
  }

Once the above is done, all routes will then go via index.html and your vue routes will take over from there.

You can place your other endpoints behind /api or something else.

Spiderman
  • 330
  • 1
  • 8
  • Yes if I remove that mapping I end up directly in my frontend. But I still cannot access http://localhost:8080/MyRoute or http://localhost:8080/myroute directly in my browser only if I click the router link I have made with GoToMyRoute – u123 Dec 12 '19 at 16:23