SpringBoot系列——Java配置(SpringMVC配置)

接下來我們來學習SpringMVC的Java配置方式,現在讓我們來快速的搭建一個springMVC項目。

實例:

1. 構建Maven項目
pom.xml內容:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.shangfu</groupId>
    <artifactId>Spring-Boot</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.7</java.version>
    </properties>

    <dependencies>
        <!--spring-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.3</version>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>jsr250-api</artifactId>
            <version>1.0</version>
        </dependency>

        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>

        <!--jstl-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
        </dependency>

        <!--使用slf4j和LogBack作爲日誌-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.0.13</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.0.13</version>
        </dependency>
        <dependency>
        <groupId>ch.qos.logback</groupId>
            <artifactId>logback-access</artifactId>
            <version>1.0.13</version>
        </dependency>

        <!--jackson-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.4.6</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.4.6</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.4.6</version>
        </dependency>

        <!--文件上傳和下載-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2. 日誌配置
在src/main/resource目錄下,新建一個logback.xml用來配置日誌,內容如下:

<?xml version="1.0" encoding="UTF-8" ?>

<!-- scan="true"    當此屬性設置爲true時,配置文件如果發生改變,將會被重新加載,默認值爲true。 -->
<!--  scanPeriod="30 seconds"   設置每30秒自動掃描,若沒有指定具體單位則以milliseconds爲標準(單位:milliseconds, seconds, minutes or hours)  -->
<!-- debug="false"當此屬性設置爲true時,將打印出logback內部日誌信息,實時查看logback運行狀態。默認值爲false。-->
<configuration  scan="true" scanPeriod="30 seconds">

    <!-- ch.qos.logback.core.ConsoleAppender 控制檯輸出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日誌消息,%n是換行符 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="console" />
    </root>
</configuration>

3. 演示界面
在src/resources下建立views目錄,並在此目錄下新建index.jsp,內容如下

<%@ page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Insert title here</title>
</head>
<body>
    <pre>
        Welcome to Spring MVC world
    </pre>
</body>
</html>

4. SpringMVC配置

@Configuration
@EnableWebMvc  //開啓SpringMVC註解
@ComponentScan("springmvc")
public class MyMvcConfig extends WebMvcConfigurerAdapter{
    @Bean
    public InternalResourceViewResolver viewResolver(){ //添加一個解析jsp的視圖解析器
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/classes/views/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setViewClass(JstlView.class);
        return viewResolver;
    }
}

你可能對路徑的前綴配置爲WEB-INF/classes/views有些奇怪,怎麼和我開發的目錄不一致,因爲看到的頁面的效果是運行時而不是開發時的代碼,運行時的代碼會將我們頁面開發自動編譯到/WEB-INF/classes/views下,所以我們的目錄就應該寫成這樣!

6. 簡單的controller

@Controller  //聲明是一個控制器
public class HelloController {
    @RequestMapping("/index") //配置URL與方法之間的映射
    public String hello(){
        return "index";  //返回試圖解析名,
    }
}

7. 運行
將程序部署到Tomcat中,啓動Tomcat,並訪問http://localhost:8080/項目名/index
結果如下:
這裏寫圖片描述

SpringMVC的常用註解

  • @Controller

    @Controller 註解在類上,表明這個類是SpringMVC中controller,將其聲明爲Spring的一個Bean,Dispatcher Servlet會自動掃描註解了次註解的類,並將web請求映射到註解了@ResquestMapping的方法上。這裏特別指出,在聲明普通的Bean的時候,使用@Component、@Service、@Repository和@Controller是等價的,但在聲明控制器的時候,只能用@Controller

  • @RequestMapping

    RequestMapping是一個用來處理請求地址映射的註解,可用於類或方法上。用於類上,表示類中的所有響應請求的方法都是以該地址作爲父路徑。
    返回值會通過視圖解析器解析爲實際的物理視圖,對於 InternalResourceViewResolver 視圖解析器,會做如下的解析:
    通過 prefix + returnVal + suffix 這樣的方式得到實際的物理視圖,然後做轉發操作;
    RequestMapping註解有六個屬性:
      1. value
      value:指定請求的實際地
      2. method
    method: 指定請求的method類型, GET、POST、PUT、DELETE等,下面例子的@PathVariable後面講解:
      3. consumes
    consumes: 指定處理請求的提交內容類型(Content-Type),例如application/json, text/html
      4. produces
    produces: 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回;
      5. params
    params: 指定request中必須包含某些參數值是,才讓該方法處理。
      6. headers
    headers: 指定request中必須包含某些指定的header值,才能讓該方法處理請求。

  • @PathVariable

    當使用@RequestMapping URI template 樣式映射時, 即 someUrl/{paramId}, 這時的paramId可通過 @Pathvariable註解綁定它傳過來的值到方法的參數上。

  • @RequestParam

    @RequestParam用於將請求參數區數據映射到功能處理方法的參數上,用例:

  • @ResponseBody 

    作用: 該註解用於將Controller的方法返回的對象,通過適當的HttpMessageConverter轉換爲指定格式後,寫入到Response對象的body數據區。
    使用時機:返回的數據不是html標籤的頁面,而是其他某種格式的數據時(如json、xml等)使用

  • @SessionAttributes

    @SessionAttributes即將值放到session作用域中,寫在class上面。  
    @SessionAttributes 除了可以通過屬性名指定需要放到會話中的屬性外(value 屬性值),
    還可以通過模型屬性的對象類型指定哪些模型屬性需要放到會話中(types 屬性值),用例:

注意: 該註解只能放在類的上面,不能放在方法上面

  • @ModelAttribute

    代表的是:該Controller的所有方法在調用前,先執行此@ModelAttribute方法,可用於註解和方法參數中,可以把這個@ModelAttribute特性,應用在BaseController當中,所有的Controller繼承BaseController,即可實現在調用Controller時,先執行@ModelAttribute方法。

  • @RestController

    我們經常見到一些控制器實現了REST的API,只爲服務於JSON,XML或其它自定義的類型內容,@RestController用來創建REST類型的控制器,與@Controller類型。@RestController就是這樣一種類型,它避免了你重複的寫@RequestMapping與@ResponseBody。

示例:

由於前面我們已經搭建好了後面學習的環境,所以後面我們直接寫代碼
1. 傳值類
封裝request對象參數和返回此對象到response

public class DemoObj implements Serializable{
    private Long id;
    private String name;
    public DemoObj(){}

    public DemoObj(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "DemoObj{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

2. 註解演示控制器

@Controller  //聲明此類是一個控制器
@RequestMapping("/anno")  //此方法的訪問路徑爲/anno
public class DemoAnnoController {
    @RequestMapping(produces = "text/plain;charset=UTF-8")  //定義返回數據類型爲json
    public @ResponseBody String index(HttpServletRequest request){  //接收參數爲HttpServletResquest
        return "url:"+request.getRequestURL()+"can access";
    }

    @RequestMapping(value="/pathvar/{str}",produces = "text/plain;charset=UTF-8")  //接收路徑參數
    public @ResponseBody String demoPathVar(@PathVariable String str, HttpServletRequest request){
        return "url:"+request.getRequestURL()+"can access"+"  str:"+str;
    }

    @RequestMapping(value="/resquestParam" ,produces = "text/plain;charset=UTF-8")  //演示常規的request參數獲取
    public @ResponseBody String passRequestParam(Long id,HttpServletRequest request){
        return "url:"+request.getRequestURL()+"can access ,id:"+id;
    }

    @RequestMapping(value="/obj" ,produces = "text/plain;charset=UTF-8")  //演示解釋參數到對象
    public @ResponseBody String passObj(DemoObj obj,HttpServletRequest request){
        System.out.println(obj);
        return "url:"+request.getRequestURL()+"can access , obj id:"+obj.getId()+"obj name:"+obj.getName();
    }

    @RequestMapping(value={"/name1","/name2"} ,produces = "text/plain;charset=UTF-8")
    public @ResponseBody String remove(HttpServletRequest request){
        return "url:"+request.getRequestURL()+"can access";
    }

}

結果:
1.訪問 localhost:8080/anno/
url:http://localhost:8080/anno/can access
2.訪問 localhost:8080/anno/pathvar/2
url:http://localhost:8080/anno/pathvar/2can access str:2
3. 訪問 localhost:8080/anno/resquestParam?id=1
url:http://localhost:8080/anno/resquestParamcan access ,id:1
4. 訪問 localhost:8080/anno/resquestParam?id=1&name=hyh
url:http://localhost:8080/anno/resquestParamcan access ,id:1
5. 訪問 localhost:8080/anno/name2
url:http://localhost:8080/anno/name2can access

MVC基本配置

SpringMVC的定製配置需要我們的配置類繼承一個 WebMvcConfigurerAdapter類,並在此類使用@EnableWebMvc註解,來開啓對SpringMVC的配置支持,這樣我們就可以重寫這個類的方法,完成我們的常用的配置。

1. 靜態資源映射

程序的靜態文件(js,css,img)等需要直接訪問,這是我們可以在配置裏重寫addResourceHandlers方法來實現

示例:

1.添加靜態資源
同上,我們在src/mian/resource/下建立一個assets/js目錄,並複製一個jquery.js的文件,放置到下面

這裏寫圖片描述

2.配置代碼
在上面的WebMvcConfig的基礎上添加下列代碼

@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //文件放置的目錄     對外暴露的訪問路徑
        registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");
    }

結果如下:
這裏寫圖片描述

2. 攔截器設置

攔截器實現對每一個請求處理前後進行相關的業務處理,類似於Servlet的Filter
可讓普通的Bean實現HanlderInterceptor接口或者繼承HandlerInterceptorAdapter類來實現自定義攔截器
通過重寫WebMvcConfigurerAdapteraddInterceptors方法來註冊自定義的攔截器,本節實例爲一個簡單的攔截器:計算每一次請求的處理時間

示例:

1.自定義攔截器

public class DemoInterceptor extends HandlerInterceptorAdapter{  //自定義攔截器
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  //請求方法前執行
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime",startTime );
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { //請求方法後執行
        long startTime = (long)request.getAttribute("startTime");
        request.removeAttribute("startTime");
        long endTime = System.currentTimeMillis();
        System.out.println("本次請求時間爲:"+ new Long(endTime-startTime)+"ms");
        request.setAttribute("handlingTime", endTime-startTime);
    }
}

2.配置
同上

    @Bean
    public DemoInterceptor demoInterceptor(){  //註冊攔截器
        return new DemoInterceptor();
    }

3.運行
這裏寫圖片描述

3.全局異常處理

通過@ControllerAdvice,我們可以將對於控制器的全局配置放置在同一個位置,註解了@Controller的類的方法可以使用@ExceptionHandlerInitBinder@ModelAttribute註解到方法上,這對左右註解了@ResquestMapping的控制器內的方法有效

  • @ExceptionHandler:用於全局處理控制器裏的異常
  • @InitBinder:用來設置WebDataBinder,WebDataBinder用來自動綁定前臺請求參數到Moder中
  • @ModerAttribute:作用是綁定鍵值到Model中

示例:

1.定製ControllerAdvice

@ControllerAdvice  //聲明控制器建言
public class ExceptionHandlerAdvice {
    @ExceptionHandler(value = Exception.class)  //攔截所有Exception異常,通過value指定
    public ModelAndView exception(Exception exception, WebRequest request){
        ModelAndView modelAndView = new ModelAndView("error");
        modelAndView.addObject("errorMessage",exception.getMessage());
        return modelAndView;
    }

    @ModelAttribute  //將鍵值對添加到Model
    public void addAttrbutes(Model model){
       model.addAttribute("msg","額外信息");
    }

    @InitBinder  //註解定製WebDataBinder
    public void initBinder(WebDataBinder webDataBinder){
        webDataBinder.setDisallowedFields("id"); //忽略請求參數id
    }

}

2.演示控制器

@Controller
public class AdviceController {
    @RequestMapping("/advice")
    public String getSomething(@ModelAttribute("msg") String msg, DemoObj obj){
        throw new IllegalArgumentException("非常抱歉,參數有誤/"+"  來自@ModelAttribute:"+msg);
    }
}

3.異常界面

public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation returns {@code null}
     */
    @Override
    public Validator getValidator() {
        return null;
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public MessageCodesResolver getMessageCodesResolver() {
        return null;
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    }

    /**
     * {@inheritDoc}
     * <p>This implementation is empty.
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
    }

}

其他的設置請自行參閱!無非就是重寫方法而已

SpringMVC高級配置

1.文件上傳配置

文件上傳是一個項目裏經常要用到的功能,SpringMVC通過配置一個MultipartResolver來上傳文件
在Spring的控制器中,通過MultipartFile file來接收文件,通過MultipartFile[] files來接收多文件上傳

示例:

1.上傳頁面

<%@ page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>upload page</title>
</head>
<body>
    <div>
        <form action="upload" enctype="multipart/form-data" method="post">
            <input type="file" name="file"/>
            <input type="submit" value="上傳"/>
        </form>
    </div>
</body>
</html>

2.添加轉向到upload頁面的ViewController

  @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/welcome").setViewName("/index");
        registry.addViewController("/toUpload").setViewName("/upload");
    }

3.MultipartResolver配置

/*文件上傳下載配置*/
    @Bean
    public MultipartResolver multipartResolver(){
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setMaxUploadSize(1000000);
        return multipartResolver;
    }

4.控制器

@Controller
public class UpAndLoadController {
    @RequestMapping(value="/upload" , method = RequestMethod.POST)
    public @ResponseBody String upload(MultipartFile file){  //使用MultipartFile file接收文件上傳
        try {
            FileUtils.writeByteArrayToFile(new File("e:/"+file.getOriginalFilename()),file.getBytes());  //將文件寫入硬盤
            return "ok";
        } catch (IOException e) {
            e.printStackTrace();
            return "wrong";
        }
    }
}

5.運行
這裏寫圖片描述
結果
這裏寫圖片描述

2.自定義HttpMessageConverter

自定義HttpMessageConverter來處理request和response數據
1.自定義HttpMessageConverter

public class MyMessageConverter extends AbstractHttpMessageConverter<DemoObj>{  
    public MyMessageConverter(){  //自定義媒體類型application/x-wisely
        super(new MediaType("application","x-wisely", Charset.forName("UTF-8")));
    }
    @Override
    protected boolean supports(Class<?> clazz) {
        return DemoObj.class.isAssignableFrom(clazz);
    }

    @Override
    protected DemoObj readInternal(Class<? extends DemoObj> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { //處理請求數據
        String temp = StreamUtils.copyToString(inputMessage.getBody(),Charset.forName("UTF-8"));
        String[] tempArr = temp.split("-");
        return new DemoObj(new Long(tempArr[0]),tempArr[1]);
    }

    @Override
    protected void writeInternal(DemoObj obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {  //處理響應數據
        String out = "hello:"+obj.getId()+"-"+obj.getName();
        outputMessage.getBody().write(out.getBytes());
    }
}

2.配置

  @Bean
    public MyMessageConverter converter(){  
        return new MyMessageConverter();
    }
    @Override  
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { //添加自己的自定義消息處理器
        converters.add(converter());
    }

3.演示控制器

@Controller
public class ConverterController  {
    @RequestMapping(value = "/convert",produces = {"application/x-wisely"}) //指定返回值類型爲我們自定義類型
    @ResponseBody  
    public DemoObj convert(DemoObj demoObj){
        return demoObj;
    }
}

4.運行

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章