Use Mixer2 with Spring MVC

SpringMVC is web application framework. It is a sub-project of springframework.

Mixer2 includes ViewResolver and AbstractView class for Spring MVC . You can use both normal html template and jsp template in controller class

Configuration

If you world like to use both Mixer2 and JSP as view engine on Spring MVC application, the DI configuration for DispatcherServlet should be as below.

    <!-- other configuration... -->
    <context:component-scan base-package="com.example.yourproject.web" />
    <mvc:annotation-driven />
    <mvc:resources mapping="/m2static/**" location="classpath:/m2mockup/m2static/" />
    <bean id="mixer2Engine" class="org.mixer2.Mixer2Engine" />
    <bean class="org.mixer2.spring.webmvc.Mixer2XhtmlViewResolver">
        <property name="order" value="1" />
        <property name="prefix" value="classpath:m2mockup/m2template/" />
        <property name="suffix" value=".html" />
        <property name="basePackage" value="com.example.yourproject.web.view" />
        <property name="mixer2Engine" ref="mixer2Engine" />
    </bean>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="order" value="2" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp"/>
    </bean>
    <!-- other configuration... -->

Java configuration.

@Configuration
@EnableAutoConfiguration
@EnableWebMvc
@ComponentScan("com.example.yourproject")
public MyConfig extends WebMvcConfigurerAdapter {

    @Bean
    public Mixer2Engine mixer2Engine() {
        return new Mixer2Engine();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/m2static/**")
                .addResourceLocations("classpath:/m2mockup/m2static/");
    }

    @Bean
    public Mixer2XhtmlViewResolver mixer2XhtmlViewResolver() {
        Mixer2XhtmlViewResolver resolver = new Mixer2XhtmlViewResolver();
        resolver.setPrefix("classpath:m2mockup/m2template/");
        resolver.setSuffix(".html");
        resolver.setBasePackage("com.example.yourproject.web.view");
        resolver.setMixer2Engine(mixer2Engine);
        resolver.setOrder(1);
        return resolver;
    }

    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/jsp/");
        resolver.setSuffix(".jsp");
        resolver.setOrder(2);
        return resolver;
    }
}

The above configuration suppose the source code tree structure as below. This is maven standard directory structure. You can use other structure with same hierarchy of classpath and document root.

src/
└── main/
    ├── java/
    │   └── com/
    │       └── example/
    │           └── yourproject/
    │               ├── Config.java // JavaConfig only
    │               ├── service/
    │               └── web/
    │                   ├── controller/
    │                   │   └── FooController.java
    │                   └── view/
    │                       └── FooView.java
    │
    ├── resources/
    │   ├── mvc-dispatcher-servlet.xml // XML config only
    │   └── m2mockup/
    │       ├── m2static/
    │       │   ├── css/
    │       │   │   └── main.css
    │       │   └── img/
    │       │       └── sample.png
    │       └── m2template/
    │           └── foo.html
    │
    └── webapp/
        └── WEB-INF/
            └── jsp/
                └── bar.jsp

Controller code

FooController class below processes the access to "/foo" URI by Mixer2, and "/bar" URI by JSP .

@Controller
public class IndexController {
    @RequestMapping(value = "/foo", method = RequestMethod.GET)
    public String foo(Model model) {
        model.addAttribute("someMessage", "Life is beautiful");
        // attach to FooView class with foo.html template
        // by Mixer2ViewResolver .
        return "foo";
    }

    @RequestMapping(value = "/bar", method = RequestMethod.GET)
    public String bar() {
        // attach to bar.jsp by InternalResourceViewResolver .
        return "bar";
    }
}

View code

You need to write FooView class as a View class for request URI "/foo" .

You need NOT to add @Component annotation because the DI configuration described above specified "com.exxample.yourproject.web.view" as "basePackage" and Mixer2ViewResolver instantiate the View class and inject bean.

...
import org.mixer2.spring.webmvc.AbstractMixer2XhtmlView;
...

public class FooView extends AbstractMixer2XhtmlView {

    // You can use any bean in DI container.
    @Autowired
    private HelloWorldBean helloWorldBean;

    @Override
    protected Html renderHtml(Html html, Map<String, Object> model, HttpServletRequest request,
            HttpServletResponse response) {

        // Mixer2ViewResolver has load "foo.html" template
        // into "html" variable automatically.
        // So, You can modify it.
        Div div = html.getById("hellomsg", Div.class);
        div.replaceInner(helloWorldBean.getHelloWorldMessageString());

        // Of course, you can use model that is delivered from controller.
        String someMessage = (String) model.get("someMessage");
        div.replaceInner(someMessage);

        // replace static file path.
        // For example: <img src="../m2static/img/sample.png" />
        // will be changed to <img src="[contextPath]/m2static/img/sample.png" />
        Pattern pattern = Pattern.compile("^\\.+/.*m2static/(.*)$");
        String ctx = request.getContextPath();
        PathAdjuster.replacePath(html, pattern, ctx + "/m2static/$1");

        return html;
    }

    @Override
    protected String modifyHtmlStringHook(String htmlStr) {
        StringBuilder sb = new StringBuilder();
        sb.append("<!--[if lt IE 9]><script src=\"/static/html5shiv.js\"></script><![endif]-->");
        sb.append("</head>");
        return htmlStr.replaceFirst("</head>", sb.toString());
    }

}

TIPS

  • Html template file is required. If nothing, Mixer2ViewResolver chains to next view resolver.
  • View class is not required. If nothing, Mixer2ViewResolver create default view class which responses html template as is.
  • Override modifyHtmlStringHook() method if you have to modify html string just before http response. See javadoc for details.

Fruit shop sample application

There are full sample web application. See Fruit shop sample application for SpringMVC and SpringBoot