EE顛覆者第四章 MVC基礎

pom

<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.wisely</groupId>
	<artifactId>highlight_springmvc4</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<properties>
		<!-- Generic properties -->
		<java.version>1.7</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<!-- Web -->
		<jsp.version>2.2</jsp.version>
		<jstl.version>1.2</jstl.version>
		<servlet.version>3.1.0</servlet.version>
		<!-- Spring -->
		<spring-framework.version>4.1.5.RELEASE</spring-framework.version>
		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>javax</groupId>
			<artifactId>javaee-web-api</artifactId>
			<version>7.0</version>
			<scope>provided</scope>
		</dependency>

		<!-- Spring MVC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- 其他web依賴 -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>
		
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${servlet.version}</version>
			<scope>provided</scope>
		</dependency>
		
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>${jsp.version}</version>
			<scope>provided</scope>
		</dependency>

		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

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

		<!--對json和xml格式的支持 -->
		<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-xml</artifactId>
			<version>2.5.3</version>
		</dependency>

		<!-- file upload -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
		</dependency>
		<!-- 非必需,可簡化IO操作 -->
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.3</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring-framework.version}</version>
			<scope>test</scope>
		</dependency>
		
	
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
			<scope>test</scope>
		</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>
			<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
		</plugins>
	</build>
</project>

日誌配置

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="1 seconds">

    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
        <resetJUL>true</resetJUL>
    </contextListener>

    <jmxConfigurator/>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>logbak: %d{HH:mm:ss.SSS} %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

      <logger name="org.springframework.web" level="DEBUG"/> <!-- 1 -->
    <root level="info">
        <appender-ref ref="console"/>
    </root>
</configuration>

index.html

src/main/resources/views下建立index.html

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<pre>
		Welcome to Spring MVC world
	</pre>
</body>
</html>

1.SpringMVC配置

繼承WebMvcConfigurerAdapter

@Configuration
@EnableWebMvc// 1
@EnableScheduling
@ComponentScan("com.wisely.highlight_springmvc4")
public class MyMvcConfig extends WebMvcConfigurerAdapter {// 2

	@Bean
	public InternalResourceViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setPrefix("/WEB-INF/classes/views/");//部署的開頭
		viewResolver.setSuffix(".jsp");
		viewResolver.setViewClass(JstlView.class);
		return viewResolver;
	}

	@Override //添加jquery.js路徑,放在 resources/assets/jquery.js  靜態資源映射
	public void addResourceHandlers(ResourceHandlerRegistry registry) {

		registry.addResourceHandler("/assets/**").addResourceLocations(
				"classpath:/assets/");// 3 對外暴漏的路徑, 本地文件放置的路徑

	}

	@Bean
	// 1   //創建攔截器
	public DemoInterceptor demoInterceptor() {
		return new DemoInterceptor();
	}

	@Override  //添加攔截器
	public void addInterceptors(InterceptorRegistry registry) {// 2
		registry.addInterceptor(demoInterceptor());
	}

	@Override //添加視圖控制,就是 返回idex 就跳轉到index頁面
	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/index").setViewName("/index");
		registry.addViewController("/toUpload").setViewName("/upload");
		registry.addViewController("/converter").setViewName("/converter");
		registry.addViewController("/sse").setViewName("/sse");
		registry.addViewController("/async").setViewName("/async");
	}

	 @Override  //末尾關閉 yy.xx 訪問yy的請求,下面會說
	 public void configurePathMatch(PathMatchConfigurer configurer) {
	 configurer.setUseSuffixPatternMatch(false);
	 }

	@Bean  //配置文件上傳的大小
	public MultipartResolver multipartResolver() {
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
		multipartResolver.setMaxUploadSize(1000000);
		return multipartResolver;
	}
	
	@Override //配置自定義消息轉換器,就是請求類型
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(converter());
    }
	
	@Bean  //創建我的消息轉換器
	public MyMessageConverter converter(){
		return new MyMessageConverter();
	}

	

}

2.啓動參數配置

實現WebApplicationInitializer

public class WebInitializer implements WebApplicationInitializer {//1

	@Override
	public void onStartup(ServletContext servletContext)
			throws ServletException {
        
		AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();//使用註解配置
        ctx.register(MyMvcConfig.class);//使用我的配置
        ctx.setServletContext(servletContext); //2
        
        Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx)); //3
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);
        servlet.setAsyncSupported(true);//1 開啓異步

	}

}

3.簡單控制器

@Controller//1
public class HelloController {
	@RequestMapping("/index")//2
	public  String hello(){
		return "index";
	}

}

4.3 Srping MVC的常用註解

public class DemoObj { //get set
	private Long id;
	private String name;
	}

produces 定製返回類型

@Controller // 1
@RequestMapping("/anno") //2
public class DemoAnnoController {

	@RequestMapping(produces = "text/plain;charset=UTF-8")	// 3
	public @ResponseBody String index(HttpServletRequest request) { // 4
		return "url:" + request.getRequestURL() + " can access";
	}

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

	@RequestMapping(value = "/requestParam", produces = "text/plain;charset=UTF-8") //6
	public @ResponseBody String passRequestParam(@RequestParam(value = "ia") Long id,
			HttpServletRequest request) {
		
		return "url:" + request.getRequestURL() + " can access,id: " + id;

	}

    //使用j'son請求穩,配置了額 id過濾,所以id爲null,json請求影響
	@RequestMapping(value = "/obj", produces = "application/json;charset=UTF-8")//7
	@ResponseBody //8
	public String passObj(@RequestBody DemoObj obj, HttpServletRequest request) {
		
		 return "url:" + request.getRequestURL() 
		 			+ " can access, obj id: " + obj.getId()+" obj name:" + obj.getName();

	}

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

}

@RestController演示

@RestController //1
@RequestMapping("/rest")
public class DemoRestController {
	
	@RequestMapping(value = "/getjson",
			produces={"application/json;charset=UTF-8"}) //2
	public DemoObj getjson (@RequestBody DemoObj obj){ //json請求 配置了額 id過濾,所以id爲null,json請求影響穩,
		return new DemoObj(obj.getId()+1, obj.getName()+"yy");//3
	}
	@RequestMapping(value = "/getxml",
			produces={"application/xml;charset=UTF-8"})//4
	public DemoObj getxml(@RequestBody DemoObj obj){
		return new DemoObj(obj.getId()+1, obj.getName()+"yy");
	}

}

靜態資源

我的MVC配置(繼承WebMvcConfigurerAdapter)重寫addResourceHandlers 配置靜態資源

攔截器

繼承HandlerInterceptorAdapter

public class DemoInterceptor extends HandlerInterceptorAdapter {//1

	@Override
	public boolean preHandle(HttpServletRequest request, //2
			HttpServletResponse response, Object handler) throws Exception {
		long startTime = System.currentTimeMillis();
		request.setAttribute("startTime", startTime);
		return true;
	}

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

}

記得配置 MyMvcConfig extends WebMvcConfigurerAdapter

ControllerAdvice

@ControllerAdvice //1
public class ExceptionHandlerAdvice { 

	@ExceptionHandler(value = Exception.class)//2
	public ModelAndView exception(Exception exception, WebRequest request) {
		ModelAndView modelAndView = new ModelAndView("error");// error頁面
		modelAndView.addObject("errorMessage", exception.getMessage()); //錯誤頁面跳轉
		return modelAndView;
	}

	@ModelAttribute //3
	public void addAttributes(Model model) {
		model.addAttribute("msg", "額外信息"); //3 ,並且添加一個附加信息
	}

	@InitBinder //4
	public void initBinder(WebDataBinder webDataBinder) {
		webDataBinder.setDisallowedFields("id"); //5  id會被過濾掉
	}
}


@Controller
public class AdviceController {
	@RequestMapping("/advice")
	public String getSomething(@ModelAttribute("msg") String msg,DemoObj obj){//1
		
		throw new IllegalArgumentException("非常抱歉,參數有誤/"+"來自@ModelAttribute:"+ msg);  //扔個錯誤,就會跳轉到錯誤頁面
	}

}


src/main/resources/views/error.jsp


<body>
	${errorMessage}
</body>




路徑匹配

默認如果點 . ,後面將會被忽略

如訪問,xx.yy .yy被忽略

	 @Override
	 public void configurePathMatch(PathMatchConfigurer configurer) {
	 configurer.setUseSuffixPatternMatch(false);//Suffix結尾
	 } //便不會被忽略

spring MVC 高級配置,文件上傳

src/main/resources/views/upload.jsp

<div class="upload">
	<form action="upload" enctype="multipart/form-data" method="post">
		<input type="file" name="file"/><br/>
		<input type="submit" value="上傳">
	</form>
</div>


	@Bean
	public MultipartResolver multipartResolver() {
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
		multipartResolver.setMaxUploadSize(1000000);
		return multipartResolver;
	}
	
@Controller
public class UploadController {
	
	@RequestMapping(value = "/upload",method = RequestMethod.POST)
	public @ResponseBody String upload(MultipartFile file) {//1
		
			try {
				FileUtils.writeByteArrayToFile(new File("e:/upload/"+file.getOriginalFilename()),
						file.getBytes()); //2
				return "ok";
			} catch (IOException e) {
				e.printStackTrace();
				return "wrong";
			}
	}
}


http://localhost:8080/highlight_springmvc4_war/toUpload

httpMessageConverter

自定義請求類型,就是 contenType


public class MyMessageConverter extends AbstractHttpMessageConverter<DemoObj> {//1

	public MyMessageConverter() {
		super(new MediaType("application", "x-wisely",Charset.forName("UTF-8")));//2
	}
	
	/**
	 * 3
	 */

	@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]);
	}
	
	/**
	 * 4
	 */
	@Override
	protected boolean supports(Class<?> clazz) {
		return DemoObj.class.isAssignableFrom(clazz);
	}
	
	/**
	 * 5
	 */
	@Override
	protected void writeInternal(DemoObj obj, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException {
		String out = "hello:" + obj.getId() + "-"
				+ obj.getName();
		outputMessage.getBody().write(out.getBytes());
	}

}




mvc配置	
	@Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(converter());
    }
	
	@Bean 
	public MyMessageConverter converter(){
		return new MyMessageConverter();
	}
@Controller
public class ConverterController {
	
	@RequestMapping(value = "/convert", produces = { "application/x-wisely" }) //1
    public @ResponseBody DemoObj convert(@RequestBody DemoObj demoObj) {
		
        return demoObj;
        
    }

}
src/main/resources/views/converter.jsp

<body>
    <div id="resp"></div><input type="button" onclick="req();" value="請求"/>
<script src="assets/js/jquery.js" type="text/javascript"></script>
<script>
    function req(){
        $.ajax({
            url: "convert",
            data: "1-wangyunfei", //1
            type:"POST",
            contentType:"application/x-wisely", //2
            success: function(data){
                $("#resp").html(data);
            }
        });
    }

</script>
</body>

http://localhost:8080/highlight_springmvc4_war/converter

會被切開 1-wangyunfei

服務推送技術

  1. SSE Server Send Event 服務端發送事件

還有雙向推送技術 WebSocket

@Controller
public class SseController {
	
	@RequestMapping(value="/push",produces="text/event-stream") //1
	public @ResponseBody String push(){
		 Random r = new Random();
        try {
                Thread.sleep(5000);
        } catch (InterruptedException e) {
                e.printStackTrace();
        }   
        return "data:Testing 1,2,3" + r.nextInt() +"\n\n";
	}

}




<body>


<div id="msgFrompPush"></div>
<script type="text/javascript" src="<c:url value="assets/js/jquery.js" />"></script>
<script type="text/javascript">


 if (!!window.EventSource) { //1
	   var source = new EventSource('push'); 
	   s='';
	   source.addEventListener('message', function(e) {//2
		   s+=e.data+"<br/>";
		   $("#msgFrompPush").html(s);
	     
	   });

	   source.addEventListener('open', function(e) {
	        console.log("連接打開.");
	   }, false);

	   source.addEventListener('error', function(e) {
	        if (e.readyState == EventSource.CLOSED) {
	           console.log("連接關閉");
	        } else {
	            console.log(e.readyState);    
	        }
	   }, false);
	} else {
	        console.log("你的瀏覽器不支持SSE");
	} 
</script>
</body>

http://localhost:8080/highlight_springmvc4_war/sse

  1. Server 3.0 + 異步方法處理

開啓異步方法

public class WebInitializer implements WebApplicationInitializer {//1

	@Override
	public void onStartup(ServletContext servletContext)
			throws ServletException {
		AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(MyMvcConfig.class);
        ctx.setServletContext(servletContext); //2
        
        //這些是開啓的代碼
        Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx)); //3
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);
        servlet.setAsyncSupported(true);//1

	}

}
@Controller //返回:DeferredResult
public class AysncController {
    @Autowired
    PushService pushService; //1

    @RequestMapping("/defer")
    @ResponseBody
    public DeferredResult<String> deferredCall() { //2
        return pushService.getAsyncUpdate();
    }

}



@Service
public class PushService {
    private DeferredResult<String> deferredResult; //1

    public DeferredResult<String> getAsyncUpdate() {
        deferredResult = new DeferredResult<String>();
        return deferredResult;
    }

    @Scheduled(fixedDelay = 5000)
    public void refresh() {
        if (deferredResult != null) {
            deferredResult.setResult(new Long(System.currentTimeMillis())
                    .toString());
        }
    }


}


src/main/resources/views/async.jsp


<body>



<script type="text/javascript" src="assets/js/jquery.js"></script>
<script type="text/javascript">

	deferred();//1
	
	function deferred(){
	    $.get('defer',function(data){
	        console.log(data); //2
	        deferred(); //3
	    });
	}


</script>
</body>

使用了定時器,記得打開 @EnableScheduling 

此方法,沒有瀏覽器兼容的問題
console.log(data); //2 查看

spring MVC 測試

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring-framework.version}</version>
			<scope>test</scope> //存活週期爲test
		</dependency>
		
	
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
			<scope>test</scope>
		</dependency>
@Service
public class DemoService {
	
	public String saySomething(){
		return "hello";
	}

}

@RestController
public class MyRestController {
	
	@Autowired
	DemoService demoService;
	
	@RequestMapping(value = "/testRest" ,produces="text/plain;charset=UTF-8")
	public @ResponseBody String testRest(){
		return demoService.saySomething();
	}

}


//@Controller
public class NormalController {
	@Autowired
	DemoService demoService;
	
	@RequestMapping("/normal")
	public  String testPage(Model model){
		model.addAttribute("msg", demoService.saySomething());
		return "page";
	}

}
src/main/resources/views/page.jsp

<body>
	<pre>
		Welcome to Spring MVC world
	</pre>
</body>

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MyMvcConfig.class})
@WebAppConfiguration("src/main/resources") //1,指定web資源的位置,默認爲src/main/webapp
public class TestControllerIntegrationTests {
	private MockMvc mockMvc; //2 模擬mvc的位置
	
	@Autowired
	private DemoService demoService;//3
	
	@Autowired 
	WebApplicationContext wac; //4
	
    @Autowired 
    MockHttpSession session; //5 注入http session
    
    @Autowired 
    MockHttpServletRequest request; //6  注入http request
    
    @Before //7 測試之前進行初始化
    public void setup() {
    	mockMvc =
    			MockMvcBuilders.webAppContextSetup(this.wac).build(); //2
    	}
	
	@Test
	public void testNormalController() throws Exception{
		mockMvc.perform(get("/normal")) //8
				.andExpect(status().isOk())//9
				.andExpect(view().name("page"))//10
				.andExpect(forwardedUrl("/WEB-INF/classes/views/page.jsp"))//11
				.andExpect(model().attribute("msg", demoService.saySomething()));//12
				
	}
	
	@Test
	public void testRestController() throws Exception{
		mockMvc.perform(get("/testRest")) //13
        .andExpect(status().isOk())
         .andExpect(content().contentType("text/plain;charset=UTF-8"))//14
        .andExpect(content().string(demoService.saySomething()));//15
	}

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