4c1cd50e4dbc26674d310d4650e3b603f610afa1
[maven-thymeleaf-skin] / src / main / java / de / juplo / thymeproxy / Application.java
1 package de.juplo.thymeproxy;
2
3 import de.juplo.thymeleaf.JuploDialect;
4 import java.util.HashMap;
5 import java.util.Locale;
6 import java.util.Map;
7 import javax.servlet.http.HttpServletRequest;
8 import javax.servlet.http.HttpServletResponse;
9 import org.apache.http.HttpStatus;
10 import org.apache.http.impl.client.CloseableHttpClient;
11 import org.springframework.beans.factory.annotation.Autowired;
12 import org.springframework.boot.SpringApplication;
13 import org.springframework.boot.autoconfigure.SpringBootApplication;
14 import org.springframework.boot.autoconfigure.web.BasicErrorController;
15 import org.springframework.boot.autoconfigure.web.ErrorAttributes;
16 import org.springframework.boot.autoconfigure.web.ErrorController;
17 import org.springframework.boot.autoconfigure.web.ErrorProperties;
18 import org.springframework.boot.autoconfigure.web.ServerProperties;
19 import org.springframework.context.annotation.Bean;
20 import org.springframework.core.Ordered;
21 import org.springframework.core.env.Environment;
22 import org.springframework.http.MediaType;
23 import org.springframework.web.servlet.ModelAndView;
24 import org.springframework.web.servlet.View;
25 import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
26 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
27 import org.springframework.web.servlet.mvc.UrlFilenameViewController;
28 import org.thymeleaf.exceptions.TemplateInputException;
29 import org.thymeleaf.resourceresolver.IResourceResolver;
30 import org.thymeleaf.resourceresolver.UrlResourceResolver;
31 import org.thymeleaf.spring4.view.ThymeleafViewResolver;
32 import org.thymeleaf.templateresolver.TemplateResolver;
33
34
35 @SpringBootApplication
36 public class Application extends WebMvcConfigurerAdapter
37 {
38   @Autowired
39   private ServerProperties properties;
40
41
42   @Bean
43   public RegexUrlHandlerMapping proxiedHandlerMapping(
44       ProxyHttpRequestHandler proxy,
45       UrlFilenameViewController views
46       )
47   {
48     RegexUrlHandlerMapping mapping = new RegexUrlHandlerMapping();
49     mapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
50     Map<String, Object> mappings = new HashMap<>();
51     mappings.put("/thymeleaf/.*\\.html", proxy);
52     mappings.put("/img/.+", proxy);
53     mappings.put("/css/.+", proxy);
54     mappings.put("/js/.+", proxy);
55     mappings.put("/fonts/.+", proxy);
56     mappings.put("/.*\\.html", views);
57     mapping.setUrlMap(mappings);
58         return mapping;
59   }
60
61   @Bean
62   public ProxyHttpRequestHandler proxyHttpRequestHandler(
63       CloseableHttpClient client,
64       Environment env
65       )
66   {
67     ProxyHttpRequestHandler handler = new ProxyHttpRequestHandler();
68     handler.setClient(client);
69     handler.setOrigin(env.getProperty("thymeproxy.origin"));
70     handler.setTtl(30000l);
71     return handler;
72   }
73
74   @Bean
75   public UrlFilenameViewController urlFilenameViewController()
76   {
77     return new UrlFilenameViewController();
78   }
79
80   @Bean
81   public TemplateResolver defaultTemplateResolver(
82       IResourceResolver resources,
83       Environment env
84       )
85   {
86     TemplateResolver resolver = new TemplateResolver();
87     resolver.setResourceResolver(resources);
88     resolver.setPrefix("http://localhost:8080/thymeleaf/");
89     resolver.setSuffix(".html");
90     resolver.setTemplateMode("HTML5");
91     resolver.setCharacterEncoding("UTF-8");
92     resolver.setCacheable(Boolean.valueOf(env.getProperty("thymeproxy.cacheable")));
93     return resolver;
94   }
95
96   @Bean
97   public TemplateResolver jsonTemplateResolver(
98       IResourceResolver resources,
99       Environment env
100       )
101   {
102     TemplateResolver resolver = new TemplateResolver();
103     resolver.setResourceResolver(resources);
104     resolver.setPrefix("http://localhost:8080/thymeleaf/");
105     resolver.setSuffix(".json");
106     resolver.setTemplateMode("JSON");
107     resolver.setCharacterEncoding("UTF-8");
108     resolver.setCacheable(Boolean.valueOf(env.getProperty("thymeproxy.cacheable")));
109     return resolver;
110   }
111
112   @Bean
113   public UrlResourceResolver thymeleafResourceResolver()
114   {
115     return new UrlResourceResolver();
116   }
117
118   @Bean
119   public JuploDialect juploDialect()
120   {
121     return new JuploDialect();
122   }
123
124   @Bean
125   public View error(ThymeleafViewResolver resolver) throws Exception
126   {
127     return resolver.resolveViewName("templates/500", Locale.getDefault());
128   }
129
130   @Bean
131   public ErrorController errorController(ErrorAttributes errorAttributes)
132   {
133     return new CustomErrorController(errorAttributes, properties.getError());
134   }
135
136
137   @Override
138   public void addViewControllers(ViewControllerRegistry registry)
139   {
140     registry.addViewController("/").setViewName("forward:index.html");
141   }
142
143
144   public static void main(String[] args)
145   {
146     SpringApplication.run(Application.class, args);
147   }
148
149
150   static class CustomErrorController extends BasicErrorController
151   {
152     public final static String TEMPLATE_INPUT_EXCEPTION =
153         TemplateInputException.class.getCanonicalName();
154
155
156     CustomErrorController(
157         ErrorAttributes errorAttributes,
158         ErrorProperties errorProperties
159         )
160     {
161       super(errorAttributes, errorProperties);
162     }
163
164
165     @Override
166     public ModelAndView errorHtml(
167         HttpServletRequest request,
168         HttpServletResponse response
169         )
170     {
171       Map<String, Object> model =
172           getErrorAttributes(
173               request,
174               isIncludeStackTrace(request, MediaType.TEXT_HTML)
175               );
176
177       String view;
178
179       switch ((String)model.get("exception"))
180       {
181         case "org.thymeleaf.exceptions.TemplateInputException":
182           response.setStatus(HttpStatus.SC_NOT_FOUND);
183           view = "templates/404";
184           break;
185
186         default:
187           response.setStatus(getStatus(request).value());
188           view = "templates/500";
189           break;
190       }
191
192       return new ModelAndView(view, model);
193     }
194   }
195 }