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