001package io.jstach.opt.spring.example.hello; 002 003import java.util.Map; 004 005import org.springframework.http.ResponseEntity; 006import org.springframework.stereotype.Controller; 007import org.springframework.web.bind.annotation.GetMapping; 008import org.springframework.web.bind.annotation.RequestParam; 009import org.springframework.web.bind.annotation.ResponseBody; 010import org.springframework.web.servlet.ModelAndView; 011import org.springframework.web.servlet.View; 012 013import io.jstach.jstache.JStacheInterfaces; 014import io.jstach.jstachio.JStachio; 015import io.jstach.jstachio.Template; 016import io.jstach.jstachio.TemplateModel; 017import io.jstach.jstachio.context.ContextNode; 018import io.jstach.opt.spring.web.JStachioHttpMessageConverter; 019import io.jstach.opt.spring.webmvc.JStachioModelView; 020 021/** 022 * Example hello world controller using different ways to use JStachio for web 023 * development. 024 * 025 * @author agentgt 026 */ 027@Controller 028public class HelloController { 029 030 /** 031 * Placate JDK 18 Javadoc 032 * @param jstachio spring powered jstachio 033 * @param view wired in template 034 */ 035 public HelloController(JStachio jstachio, Template<HelloModel> view) { 036 this.jstachio = jstachio; 037 this.view = view; 038 } 039 040 /** 041 * (Optional) Spring will inject this template as the templates are either component 042 * scanned or loaded by the ServiceLoader into Spring's context. 043 * 044 * This is usually not needed as just returning the models is good enough. 045 */ 046 public final Template<HelloModel> view; 047 048 /** 049 * Although not needed You can also wire in JStachio directly 050 */ 051 public final JStachio jstachio; 052 053 /** 054 * Here we use JStachio runtime to resolve the renderer (in this case we are calling 055 * them Views) via Springs Http Message Converter. 056 * @apiNote Notice that the method has to be annotated with 057 * <code>@ResponseBody</code>. 058 * @return the model that will be used to find the correct view and then rendered 059 * using that view 060 * @see JStachioHttpMessageConverter 061 */ 062 @GetMapping(value = "/") 063 @ResponseBody 064 public HelloModel hello() { 065 return new HelloModel("Spring Boot is now JStachioed!"); 066 } 067 068 /** 069 * Here we use the generated code directly and return a {@link TemplateModel} which is 070 * analogous to {@link ModelAndView}. 071 * 072 * @apiNote Notice that the method has to be annotated with 073 * <code>@ResponseBody</code>. 074 * @return the template model pair that already has the template found. 075 * @see JStachioHttpMessageConverter 076 */ 077 @GetMapping(value = "/templateModel") 078 @ResponseBody 079 public TemplateModel templateModel() { 080 return HelloModelView.of().model(new HelloModel("Spring Boot is using JStachio TemplateModel!")); 081 } 082 083 /** 084 * Here we use a {@link ResponseEntity} which allows use to set status codes with our 085 * model to be rendered. 086 * @return a response entity. 087 * @see JStachioHttpMessageConverter 088 */ 089 @GetMapping(value = "/responseEntity") 090 public ResponseEntity<HelloModel> entity() { 091 return ResponseEntity.badRequest().body(new HelloModel("Spring Boot is using JStachio ResponseEntity. " 092 + "This is a 400 http error code but is not an actual error!")); 093 } 094 095 /** 096 * Here we could use {@link JStacheInterfaces} to make our model implement 097 * {@link JStachioModelView} to support the traditional servlet MVC approach. The 098 * model will use the static jstachio singleton that will be the spring one. 099 * <p> 100 * This approach has pros and cons. It makes your models slightly coupled to Spring 101 * MVC but allows you to return different views if say you had to redirect on some 102 * inputs ({@link org.springframework.web.servlet.view.RedirectView}). 103 * 104 * @apiNote Notice that the return type is {@link View}. 105 * @return the model and view that will be used as View (see 106 * {@link HelloModelAndView}). 107 * @see JStachioHttpMessageConverter 108 * @see HelloModelAndView 109 */ 110 @GetMapping(value = "/mvc") 111 @SuppressWarnings("exports") 112 public View mvc() { 113 return new HelloModelAndView("Spring Boot MVC is now JStachioed!"); 114 } 115 116 /** 117 * Here we show MVC model support which will be bound to 118 * {@value ContextNode#CONTEXT_BINDING_NAME}. 119 * @param model Spring provided model map to be filled 120 * @return the model and view 121 */ 122 @GetMapping(value = "/context") 123 @SuppressWarnings("exports") 124 public View context(Map<String, Object> model) { 125 model.put("csrf", "CSRF_TOKEN"); 126 return new HelloModelAndView("Spring Boot MVC is now JStachioed with csrf!"); 127 } 128 129 /** 130 * Here we use the {@linkplain #view wired renderer}. 131 * @return template model pair derived from {@link Template#model(Object)}. 132 */ 133 @GetMapping(value = "/wired") 134 @ResponseBody 135 public TemplateModel wired() { 136 var model = new HelloModel("JStachioed is wired!"); 137 return view.model(model); 138 } 139 140 /** 141 * Here we could use {@link JStacheInterfaces} to make our model implement 142 * {@link JStachioModelView} to support the traditional servlet MVC approach. The 143 * model will use the static jstachio singleton that will be the spring one. 144 * <p> 145 * This approach has pros and cons. It makes your models slightly coupled to Spring 146 * MVC but allows you to return different views if say you had to redirect on some 147 * inputs ({@link org.springframework.web.servlet.view.RedirectView}). 148 * <p> 149 * 150 * This controller method is to test buffering. Ignore. 151 * 152 * @apiNote Notice that the return type is {@link View}. 153 * @param size size of output 154 * @return the model and view that will be used as View (see 155 * {@link HelloModelAndView}). 156 * @see JStachioHttpMessageConverter 157 * @see HelloModelAndView 158 * @hidden 159 */ 160 @GetMapping(value = "/long/mvc") 161 @SuppressWarnings("exports") 162 public View longMvc(@RequestParam(name = "size", defaultValue = "0") int size) { 163 if (size <= 0) { 164 size = 1024 * 16; 165 } 166 StringBuilder sb = new StringBuilder(); 167 for (int i = 0; i < size; i++) { 168 int j = (i % 64) + 48; 169 char c = (char) j; 170 sb.append(c); 171 } 172 return new HelloModelAndView(sb.toString()); 173 } 174 175}