1. 程式人生 > >SpringMVC純註解配置web.xml、json、靜態資源、thymeleaf,遞迴json陣列

SpringMVC純註解配置web.xml、json、靜態資源、thymeleaf,遞迴json陣列

一些前面寫過的(註解配置SpringMVC+Thymeleaf)這裡將不重複多講,該文章主要寫如何註解配置靜態資源、json converter,也有一些乾貨,由於搜不到一些遞迴json物件陣列的jquery方法所以自己編寫了一個遞迴輸出json的方法。

Spring配置個人分為3個方面:

(1)容器配置(可通過web.xml或進行)

(2)根配置(資料層、常用Bean的配置,可通過xml檔案或類進行配置)

(3)Servlet配置(配置頁面所需bean,可通過xml檔案或類進行配置)

1.容器配置:

無web.xml檔案時Maven專案需在外掛處新增以下設定(當xml不存在時不報錯):

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
</plugin>

通過類配置代替web.xml配置時配置類需實現WebApplicationInitializer介面或繼承該介面的實現類,該實現類詳解可看第一段連結的文章,以下是該文章的web.xml配置類

WebInitializer.java

package per.mvc.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import per.mvc.controller.WebConfig;


/**
 * Created by Wilson on 2017/5/21.
 */
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    protected 
Class<?>[] getRootConfigClasses() { return new Class<?>[0]; } protected Class<?>[] getServletConfigClasses() { return new Class<?>[]{WebConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } }

2.根配置(配置資料來源、資料介面等,發現之前寫Thyleaf時沒有寫註解配置資料層,但由於該文章主題不是這個,所以該部分程式碼會以個人的以往例子配置貼到文章末尾給大家參考,但不會進行過多講解)

3.Servlet配置

package per.mvc.controller;

import static com.alibaba.fastjson.serializer.SerializerFeature.*;

import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4;
import com.google.common.collect.Lists;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ITemplateResolver;


import java.nio.charset.Charset;
import java.util.List;


/**
 * Created by Wilson on 2017/5/21.
 */
@EnableWebMvc
@Configuration
@ComponentScan
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Bean
    public ITemplateResolver templateResolver() {
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setPrefix("/WEB-INF/");
        templateResolver.setSuffix(".html");
        templateResolver.setCharacterEncoding("UTF-8");
        return templateResolver;
    }

    @Bean
    public TemplateEngine templateEngine(ITemplateResolver templateResolver) {
        TemplateEngine templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver(TemplateEngine templateEngine) {
        ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
        thymeleafViewResolver.setTemplateEngine(templateEngine);
        thymeleafViewResolver.setContentType("text/html;charset=utf-8");
        return thymeleafViewResolver;
    }

    @Override	//配置預設資訊轉換器,需擴充套件則複寫extendMessageConverters方法
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter4 fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter4();
        /*
            <property name="supportedMediaTypes">
                    <list>
                        <value>text/plain;charset=UTF-8</value>
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                    </list>
            </property>
            上述xml配置相當於以下程式碼段,至於JSON的配置用的是阿里的fastjson,因Spring的json配置主要查詢HttpMessageConverter介面的實現類及其子類,
            所以並非固定要用官方的
        */
        fastJsonHttpMessageConverter.setSupportedMediaTypes(Lists.newArrayList(
                MediaType.APPLICATION_JSON_UTF8, new MediaType(MediaType.TEXT_HTML, Charset.forName("UTF-8")), new MediaType(MediaType.TEXT_PLAIN, Charset.forName("UTF-8"))));
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(DisableCircularReferenceDetect, QuoteFieldNames,WriteNonStringKeyAsString,
                WriteNullListAsEmpty,WriteNullBooleanAsFalse,WriteMapNullValue,WriteNullStringAsEmpty);
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
        converters.add(fastJsonHttpMessageConverter);
    }

   /* @Override     //由於已使用預設靜態資源處理,所以該方法省去,只用於講解
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //相當於 <mvc:resources mapping="/**" location="/img/" /> 也可設定多個路徑
        registry.addResourceHandler("/**").addResourceLocations("/img/");
        registry.addResourceHandler("/**","/**").addResourceLocations("/js","/css/");
    }*/
}
以下是設定靜態資源處理方法的原始碼,基於特定的URL路徑樣式為服務頁面的靜態資源新增資源處理器。該方法的引數位URL路徑pattern,即靜態資源的投影路徑(對應xml的mapping),該方法返回物件用於設定資原始檔的相對路徑(呼叫該物件的addResourceLocation),相當於xml配置中的location

/**
 * Add a resource handler for serving static resources based on the specified URL path
 * patterns. The handler will be invoked for every incoming request that matches to
 * one of the specified path patterns.
 * <p>Patterns like {@code "/static/**"} or {@code "/css/{filename:\\w+\\.css}"}
 * are allowed. See {@link org.springframework.util.AntPathMatcher} for more details on the
 * syntax.
 * @return A {@link ResourceHandlerRegistration} to use to further configure the
 * registered resource handler
 */
public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) {
   ResourceHandlerRegistration registration =
         new ResourceHandlerRegistration(this.applicationContext, pathPatterns);
   this.registrations.add(registration);
   return registration;
}
控制層:

package per.mvc.controller;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import per.mvc.pojo.UserInfo;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Wilson on 2017/5/21.
 */
@Controller
@RequestMapping("/")
public class BaseController {
    @RequestMapping("/")
    public String home(){
        return "index";
    }
    @RequestMapping("/index")
    public String index(){
        return "index";
    }
    @RequestMapping(value = "/obj")
    @ResponseBody
    public String obj(){
        return JSON.toJSONString(new UserInfo("Wilson-何","blog.csdn.net/z28126308"));
    }

    @RequestMapping(value = "/map")
    @ResponseBody
    public Map getMap(){
        Map map = new HashMap();
        map.put("data",Lists.newArrayList(new UserInfo("nameA","addressA"),new UserInfo("nameB","addressB")));
        return map;
    }
}

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script th:src="@{/js/jquery-1.8.3.js}"></script>
    <script th:src="@{/js/index.js}"></script>
    <link th:href="@{/css/font.css}" rel="stylesheet" type="text/css"/>
</head>
<body>
我是一個有樣式的頁面<br>
<button>first click</button>
<button>last click</button>
<div contenteditable="true"></div>
</body>
</html>

這裡有點小細節需注意,若在mvc配置類中沒有進行預設靜態處理器的使能th:src的路徑將無法訪問,靜態資源個人都放在webapp目錄下,呼叫了以下方法後通過thymeleaf模板即可訪問webapp目錄下的靜態資源,也可通過addResourceHandlers方法配置而不需啟用預設處理,但一般都推薦使用預設靜態資源處理器處理

啟用預設靜態資源處理:

public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}

自定義靜態資源處理(效果同上)

@Override     //若已使用靜態處理則可省略該方法,pathPatterns的“/”路徑是webapp下的路徑,而不是/webapp/WEB-INF
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**").addResourceLocations("/");
}

index.js(遞迴函式用於拼接遞迴後臺傳過來的各種解析後的JSON資料,由於百度到很多都只能遍歷單個物件於是編寫了該方法進行遞迴拼接)

/**
 * Created by Wilson on 2017/5/22.
 */
$(function () {
    $("button:first").on("click", function () {
        $.ajax({
            url: "obj",
            type: "GET",
            success: function (result) {
                $("div").append("object json:<br>" + result + "<br>"
                    + "parse object json:<br>" + ergodic($.parseJSON(result)) + "<hr/>");
            }
        })
    })
    $("button:last").on("click", function () {
        $.ajax({
            url: "map",
            type: "GET",
            success: function (responseText) {
                $("div").append("parse map json:<br>" + ergodic(responseText) + "<hr/>");
            }
        })
    })
})

//遞迴拼接字串
function ergodic(obj) {
    var content = "";
    $.each(obj, function (key, value) {
        //檢測到值若為物件則繼續遞迴進行拼接
        if ($.type(value) == "object") {
            content += key + ":" + "{" + ergodic(value) + "}<br>";
        }
        //檢測到值若為陣列則繼續遞迴進行拼接
        else if ($.type(value) == "array") {
            content += key + ":" + "[<br>" + ergodic(value) + "]<br>";
        }
        //檢測到值若既非陣列又非物件則連線鍵值
        else {
            content += key + ":" + value + ",";
        }
    })
    content = content.replace(/,}/, "}");
    content = content.replace(/,$/, "");
    return content;
}

專案目錄圖:

分別點選2個按鈕後的頁面結果圖:





由於之前都沒有寫過資料層的註解配置,所以下面會提供一個mybatis資料層配置類代替xml配置給大家提供參考,包括了使用時還需在容器配置類的getRootConfigClasses方法中新增該類,如

protected Class<?>[] getRootConfigClasses() {
    return new Class<?>[]{RootConfig.class};
}
RootConfig.java

package pers.graduation.config;

import java.util.Properties;

import javax.sql.DataSource;

import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.core.io.Resource;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.stereotype.Repository;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan(basePackages = "pers", excludeFilters = {
      @Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class) })
public class RootConfig {
   @Bean
   protected DataSource getDataSource() {
      DriverManagerDataSource dataSource = new DriverManagerDataSource();
      dataSource.setUrl(
            "jdbc:mysql://localhost/****?serverTimezone=GMT");
      dataSource.setUsername("root");
      dataSource.setPassword("****");
      dataSource.setDriverClassName("com.mysql.jdbc.Driver");
      return dataSource;
      /*
       * JndiObjectFactoryBean factory = new JndiObjectFactoryBean();
       * factory.setJndiName("jdbc/orcl"); return (DataSource)
       * factory.getObject();
       */
   }

   @Bean
   protected DataSourceTransactionManager getTransactionManager(DataSource dataSource) {
      DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
      return transactionManager;
   }

   @Bean("sqlSessionFactory")
   @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
   protected SqlSessionFactoryBean getSqlSessionFactory(DataSource dataSource,PageInterceptor pageInterceptor) throws Exception {
      SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
      factory.setDataSource(dataSource);
      ClassPathResource resource = new ClassPathResource("mybatis-config.xml");
      factory.setConfigLocation(resource);
      factory.setPlugins(new Interceptor[]{pageInterceptor});
      return factory;
   }

   @Bean		
   @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
   public MapperScannerConfigurer getMapperScannerConfigurer() {
      MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
      mapperScannerConfigurer.setBasePackage("xxx.xxx.dao");
      mapperScannerConfigurer.setAnnotationClass(Repository.class);
      mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
      mapperScannerConfigurer.setProperties(new Properties(){{put("mappers", "xxx.xxx.dao.base.BaseMapper");}});
      return mapperScannerConfigurer;
   }

   @Bean		//配置mybatis分頁外掛
   public PageInterceptor getPageInterceptor(){
      PageInterceptor pageInterceptor = new PageInterceptor();
      Properties properties = new Properties();
      properties.put("helperDialect","mysql");
      properties.put("offsetAsPageNum","true");
      properties.put("reasonable","true");
//    properties.put("rowBoundsWithCount","true");
      properties.put("pageSizeZero","true");
      properties.put("params","pageNum=start;pageSize=limit;pageSizeZero=zero;count=countSql");
      properties.put("supportMethodsArguments","true");
      pageInterceptor.setProperties(properties);
      return pageInterceptor;
   }
}

該文章的例項可以到我的部落格資源處下載