SpringBoot-VueJSadds VueJS to a Spring-boot Project for Creating Client-Side Application Logic Within Spring Controllers.
Insert the dependency in your pom.xmlfile:
<dependency>
<groupId>io.github.jeemv.springboot.vuejs</groupId>
<artifactId>springboot-vuejs</artifactId>
<version>[1.0,)</version>
</dependency>@Controller@RequestMapping("/ui/")
publicclassUiTest {
@GetMapping("test")
publicStringindex(ModelMapmodel) {
VueJSvue=newVueJS("#app");
vue.addData("message", "Hello world!");
model.put("vue", vue);
return"index";
}
}The index.html mustache view:
<divid="app"><%message%><inputv-model="message"></div>
{{{vue}}}Mustache view use double mustache for variables (message in the example), so the VueJS instance is set by default to use <% and %> as delimiters.
The vue variable generates the javascript code for the view instance creation. The triple mustache {{{vue}}}is use for javascript/html code unescaping.
This technique has the advantage of providing a globale instance of VueJS for all the actions of a controller. Create a configuration class to allow the autowiring of VueJS:
@Configuration@ComponentScan("io.github.jeemv.springboot.vuejs")
publicclassAppConfiguration {
}In your controller:
@Controller@RequestMapping("/ui/")
publicclassUiTest {
@AutoWiredprivateVueJSvue;
@ModelAttribute(name = "vue")
privateVueJSgetVue() {
returnthis.vue;
}
@GetMapping("test")
publicStringindex(ModelMapmodel) {
vue.addData("message", "Hello world!");
return"index";
}
}In this case, you can directly configure VueJS in the application.properties file:
springboot.vuejs.delimiters=<%,%>
springboot.vuejs.axios=true
springboot.vuejs.el=v-appFor a more punctual use, in a single method for example, It is possible to use the @ModelAttribute annotation :
@Controller@RequestMapping("/ui/")
publicclassUiTest {
@ModelAttribute("vue")
publicVueJSgetVue() {
returnnewVueJS("#app");
}
@GetMapping("test")
publicStringindex(@ModelAttribute("vue") VueJSvue) {
vue.addData("message", "Hello world!");
return"index";
}
}AOP loading in pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>AOP activation in app config file:
@Configuration@ComponentScan("io.github.jeemv.springboot.vuejs.aspects")
@EnableAspectJAutoProxypublicclassAppConfig {
}AOP usage in controller:
@Controller@RequestMapping("/ui/")
publicclassUiTest {
@GetMapping("test")
@VueJSInstancepublicStringtest2(VueJSvue,ModelMapmodel) {
vue.addData("message", "Hello world!");
return"index";
}
}Adds data object for the Vue instance.
vue.addData("visible",false);
vue.addData("group",group);//where group is an instance of the class Groupvue.addData("users",users);//where users is an ArrayList of UserAdds a method to the vue instance
vue.addMethod("toggleVisible", "this.visible=!this.visible;");
vue.addMethod("addScore","this.scores.push(score)","score");Adds a computed property to the vue instance
vue.addComputed("count", "return this.users.length");A computed property can have a setter:
vue.addMethod("fullname","return this.firstName + ' ' + this.lastName;","var names = newValue.split(' '); this.firstName = names[0]; this.lastName = names[names.length - 1];");Adds a watcher on variable to the view instance
vue.addWatcher("value", "'value was '+oldValue+'. It is now '+val;");It is possible to create components at runtime, but it is more efficient to generate them before:
publicclassCompoButton {
publicstaticvoidmain (String[] args) throwsjava.lang.Exception {
VueComponentcompo=newVueComponent("button-counter");
compo.addData("count", 0);
compo.setTemplate("<button @click=\"count++\">You clicked me {{ count }} times.</button>");
compo.createFile(false);
}
}The generated file is created in {project-folder}/src/main/resources/static/vueJS/button-counter.js
//Script generated with VueComponent at Thu Oct 11 03:01:09 CEST 2018Vue.component('button-counter',{"data":function(){return{"count":0};},"template":"<button @click=\"count++\">You clicked me {{ count }} times.</button>"});Usage:
<scriptsrc="/vueJS/button-counter.js"></script>
...
<button-counter></button-counter>Templates are easier to create in a file:
Create the file /src/main/resources/templates/vueJS/button-counter.html
<button@click="count++">
You clicked me {{ count }} times.
</button>Modify the class CompoButton:
publicclassCompoButton {
publicstaticvoidmain (String[] args) throwsjava.lang.Exception {
VueComponentcompo=newVueComponent("button-counter");
compo.addData("count", 0);
compo.setDefaultTemplateFile();
compo.createFile(false);
}
}the generated file is the same, but the method is more convenient.
Default delimiters are <% and %>.
For changing the plain text interpolation delimiters and avoid conflict with other template packages, you can modify them with:
vue.setDelimiters("{!","!}");You can also generate code to perform ajax queries:
vue.addMethod("submit",Http.postForm("formRef","console.log('submit datas!')"));HTTP calls from Vue.js to SpringBoot REST backend:
vue.addMethod("saveUser",Http.post("user/","user","console.log('User added!')"),"user");
vue.addMethod("updateUser",Http.put("user/","user","console.log('User updated!')"),"user");For axios, Do not forget to include the corresponding js file.
The javascript code is sometimes too large to be neatly integrated into a java controller. In this case, it can be delocalized in a javascript file, which can refer to java variables of the controller.
The java variables are parsed with ${varName} usage.
//resource/static/js/sample.jsconsole.log("${message}");@GetMapping("sample")
publicStringtestJs(@ModelAttribute("vue") VueJSvue) throwsIOException {
JavascriptResourcejs = JavascriptResource.create("sample");
js.put("message", "Hello world!");
vue.addMethod("click", js.parseContent());
return"view";
}To avoid the multiplicity of javascript files, it is possible to group several scripts in the same file.
Each script (qualified as a module) must be identified in the javascript file by a comment on a single line bearing its name, and a comment marking the end (also mentioning the name of the script).
Each script can possibly be isolated, which is without consequences.
//resource/static/js/multi.js//----------------consoleMsg-----------------------console.log("${message}");//----------------consoleMsg (end)-----------------//----------------alertMsg-------------------------(function(){alert("${message}");})();//----------------alertMsg (end)-------------------@GetMapping("sample")
publicStringtestJsMulti(@ModelAttribute("vue") VueJSvue) throwsIOException {
JavascriptMultiModulesResourcejsMulti=JavascriptMultiModulesResource.create("multi");
jsMulti.getModule("consoleMsg").put("message", "This is a console message");
vue.addMethod("click", js.parseContent("consoleMsg"));
return"view";
}