第4章 Spring MVC基础
来源:互联网 发布:手机mac地址伪装 编辑:程序博客网 时间:2024/06/01 17:38
第4章 Spring MVC基础
4.1 Spring MVC概述
MVC:Model + View + Controller (数据模型 + 试图 + 控制器)。
三层架构:Presentation tier + Application tier + Data tier(展现层 + 应用层 + 数据访问层)。
MVC是三层架构的展现层,M实际上是数据模型,是包含数据的对象,用来和V之间的数据交互,V是视图页面,C当然就是控制器。
三层架构是整个应用的架构,是由Spring框架负责管理的。项目结构中Service层对应应用层,DAO层对应数据访问层。
4.2 Spring MVC项目快速搭建
4.2.1 点睛
Spring MVC提供了一个DispatcherServlet来开发Web应用。在Servlet2.5及以下的时候只要在web.xml下配置元素即可。在Servlet3.0,实现WebApplicationInitializer接口便可实现等同于web.xml的配置。
4.2.2 示例
package com.wisely.highlight_springmvc4;import java.util.List;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.web.multipart.MultipartResolver;import org.springframework.web.multipart.commons.CommonsMultipartResolver;import org.springframework.web.servlet.config.annotation.EnableWebMvc;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import org.springframework.web.servlet.view.InternalResourceViewResolver;import org.springframework.web.servlet.view.JstlView;import com.wisely.highlight_springmvc4.interceptor.DemoInterceptor;import com.wisely.highlight_springmvc4.messageconverter.MyMessageConverter;@Configuration@EnableWebMvc// 1注解会开启一些默认配置@ComponentScan("com.wisely.highlight_springmvc4")public class MyMvcConfig extends WebMvcConfigurerAdapter {// 2运行时代码会将我们的页面自动编译到/WEB-INF/classes/views下 @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/classes/views/"); viewResolver.setSuffix(".jsp"); viewResolver.setViewClass(JstlView.class); return viewResolver; }}
package com.wisely.highlight_springmvc4;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.ServletRegistration.Dynamic;import org.springframework.web.WebApplicationInitializer;import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;import org.springframework.web.servlet.DispatcherServlet;public class WebInitializer implements WebApplicationInitializer { //1WebApplicationInitializer是Spring提供用来配置Servlet3.0 + 配置的接口,从而实现了替代Web.xml的位置。 //实现此接口将会自动被SpringServletContainerInitializer(用来启动Servlet3.0容器)获取到。 @Override public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(MyMvcConfig.class); ctx.setServletContext(servletContext); //2新建WebApplicationContext,注册配置类,并将其和当前servletContext关联 Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx)); //3注册Spring MVC的DispatcherServlet servlet.addMapping("/"); servlet.setLoadOnStartup(1); servlet.setAsyncSupported(true);//1 }}
4.3 Spring MVC的常用注解
4.3.1 点睛
(1)@Controller
(2)@RequestMapping
(3)@ResponseBody
(4)@RequestBody
(5)@PathVariable 用来接受路径参数
(6)@RestController是一个组合注解,组合了@Controller和@ResponseBody。
4.3.2 示例
package com.wisely.highlight_springmvc4.web.ch4_3;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import com.wisely.highlight_springmvc4.domain.DemoObj;@Controller // 1@RequestMapping("/anno") //2public class DemoAnnoController { @RequestMapping(produces = "text/plain;charset=UTF-8") // 3produces可定制返回的response的媒体类型和字符集 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(Long id, HttpServletRequest request) { return "url:" + request.getRequestURL() + " can access,id: " + id; } @RequestMapping(value = "/obj", produces = "application/json;charset=UTF-8")//7 @ResponseBody //8 public String passObj(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"; }}
4.4 Spring MVC基本配置
Spring MVC的定制配置需要我们的配置类继承一个WebMvcConfigurerAdapter类,并在此类使用@EnableWebMvc注解,来开启对Spring MVC的配置支持,这样我们就可以重写这个类的方法,完成我们的常用配置。
4.4.1 静态资源映射
1.点睛
程序的静态文件(js、css、图片)等需要直接访问,这时我们可以在配置里重写addResourceHandlers方法来实现。
2.示例
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/assets/**").addResourceLocations( "classpath:/assets/"); // 3 addResourceLocations指的是文件放置的目录,addResourceHandler指的是对外暴露的访问路径 }
4.4.2 拦截器配置
1点睛
拦截器(Interceptor)实现对每一个请求处理前后进行相关的业务处理,类似于Servlet的Filter。
可让普通的Bean实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter类来实现自定义拦截器。
通过重写WebMvcConfigurerAdapter的addInterceptors方法来注册自定义的拦截器
2.示例
package com.wisely.highlight_springmvc4.interceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;public class DemoInterceptor extends HandlerInterceptorAdapter { //1继承HandlerInterceptorAdapter类来实现自定义拦截器 @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("本次请求处理时间为:" + new Long(endTime - startTime)+"ms"); request.setAttribute("handlingTime", endTime - startTime); }}
@Override public void addInterceptors(InterceptorRegistry registry) { // 2重写addInterceptors方法,注册拦截器 registry.addInterceptor(demoInterceptor()); }
4.4.3 @ControllerAdvice
1.点睛
通过@ControllerAdvice,可以将对于控制器的全局配置放置在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上,这对所有注解了@RequestMapping的控制器内的方法有效。
@ExceptionHandler:用于全局处理控制器里的异常。
@InitBinder:用来设置WebDataBinder,WebDataBinder用来自动绑定到前台请求参数到Model中。
@ModelAttribute:@ModuelAttribute本来的作用是绑定键值对到Model里,此处是让全局的@RequestMapping都能获得在此设置的键值对。
2示例
package com.wisely.highlight_springmvc4.advice;import org.springframework.ui.Model;import org.springframework.web.bind.WebDataBinder;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.InitBinder;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.context.request.WebRequest;import org.springframework.web.servlet.ModelAndView;@ControllerAdvice //1public class ExceptionHandlerAdvice { @ExceptionHandler(value = Exception.class) //2定义全局处理,通过@ExceptionHandler的value属性可过滤拦截的条件 public ModelAndView exception(Exception exception, WebRequest request) { ModelAndView modelAndView = new ModelAndView("error");// error页面 modelAndView.addObject("errorMessage", exception.getMessage()); return modelAndView; } @ModelAttribute //3 将键值对添加到全局,所有注解的@RequestMapping的方法可获得此键值对 public void addAttributes(Model model) { model.addAttribute("msg", "额外信息"); //3 } @InitBinder //4 public void initBinder(WebDataBinder webDataBinder) { webDataBinder.setDisallowedFields("id"); //5 }}
package com.wisely.highlight_springmvc4.web.ch4_4;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.bind.annotation.RequestMapping;import com.wisely.highlight_springmvc4.domain.DemoObj;@Controllerpublic class AdviceController { @RequestMapping("/advice") public String getSomething(@ModelAttribute("msg") String msg,DemoObj obj){//1 throw new IllegalArgumentException("非常抱歉,参数有误/"+"来自@ModelAttribute:"+ msg); }}
4.4.4 其他配置
1 快捷的ViewController
@RequestMapping("/index")//2public String hello(){ return "index";}
可以通过在配置中重写addViewControllers来简化配置:
@Overridepublic void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/index").setViewName("/index");}
2.路径匹配参数配置
在Spring MVC中,路径参数如果带“.”的话,“.”后面的置将被忽略。
通过重写configurePathMatch方法可不忽略“.”后面的参数。
@Override public void configurePathMatch(PathMatchConfigurer configurer) { configurer.setUseSuffixPatternMatch(false); }
3.更多配置
更多配置请查看WebMvcConfigurerAdapter类的API。
4.5 Spring MVC的高级配置
4.5.1 文件上传配置
1.点睛
Spring MVC通过配置一个MultipartResolver来上传文件。
在Spring的控制器中,通过MultipartFile file来接收文件,通过MultipartFile[] files接收多个文件上传。
2.示例
@Beanpublic MultipartResolver multipartResolver() { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setMaxUploadSize(1000000); return multipartResolver;}
package com.wisely.highlight_springmvc4.web.ch4_5;import java.io.File;import java.io.IOException;import org.apache.commons.io.FileUtils;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.multipart.MultipartFile;@Controllerpublic class UploadController { @RequestMapping(value = "/upload",method = RequestMethod.POST) public @ResponseBody String upload(MultipartFile file) { //1使用MultipartFile file接收上传的文件 try { FileUtils.writeByteArrayToFile(new File("e:/upload/"+file.getOriginalFilename()), file.getBytes()); //2 使用FileUtils.writeByteArrayToFile快速写文件到磁盘 return "ok"; } catch (IOException e) { e.printStackTrace(); return "wrong"; } }}
4.5.2 自定义HttpMessageConverter
1.点睛
HttpMessageConverter是用来处理request和response里的数据的。
2示例
package com.wisely.highlight_springmvc4.messageconverter;import java.io.IOException;import java.nio.charset.Charset;import org.springframework.http.HttpInputMessage;import org.springframework.http.HttpOutputMessage;import org.springframework.http.MediaType;import org.springframework.http.converter.AbstractHttpMessageConverter;import org.springframework.http.converter.HttpMessageNotReadableException;import org.springframework.http.converter.HttpMessageNotWritableException;import org.springframework.util.StreamUtils;import com.wisely.highlight_springmvc4.domain.DemoObj;public class MyMessageConverter extends AbstractHttpMessageConverter<DemoObj> { //1继承AbstractHttpMessageConverter接口来实现自定义的HttpMessageConverter public MyMessageConverter() { super(new MediaType("application", "x-wisely",Charset.forName("UTF-8"))); //2新建一个我们自定义的媒体类型application/x-wisely } /** * 3重写readIntenal方法,处理请求的数据 */ @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表明本HttpMessageConverter只处理DemoObj这个类 */ @Override protected boolean supports(Class<?> clazz) { return DemoObj.class.isAssignableFrom(clazz); } /** * 5重写writeInternal,处理如何输出数据到response。 */ @Override protected void writeInternal(DemoObj obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { String out = "hello:" + obj.getId() + "-" + obj.getName(); outputMessage.getBody().write(out.getBytes()); }}
@Override//extendMessageConverters:仅添加一个自定义的HttpMessageConverter,不覆盖默认注册的HttpMessageConverter。//configureMessageConverters:重载会覆盖掉Spring MVC默认注册的多个HttpMessageConverter。 public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(converter()); }@Bean public MyMessageConverter converter(){ return new MyMessageConverter();}
package com.wisely.highlight_springmvc4.web.ch4_5;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import com.wisely.highlight_springmvc4.domain.DemoObj;@Controllerpublic class ConverterController { @RequestMapping(value = "/convert", produces = { "application/x-wisely" }) //1 public @ResponseBody DemoObj convert(@RequestBody DemoObj demoObj) { return demoObj; }}
function req(){ $.ajax({ url: "convert", data: "1-wangyunfei", //1 type:"POST", contentType:"application/x-wisely", //2 success: function(data){ $("#resp").html(data); } });}
4.5.3 服务端推送技术
服务端推送的方案都是基于:当客户端向服务端发送请求,服务端会抓住这个请求不放,等有数据更新的时候才返回给客户端,当客户端接收到消息后,再向服务端发送请求,周而复始。
除了服务端推送技术以外,还有一个另外的双向通信的技术——WebSocket,后面介绍。
基于SSE(Server Send Event 服务端发送事件)的服务器端推送(需要新式浏览器的支持)和基于Servlet3.0+的异步方法特性(跨浏览器的)。
1.SSE
package com.wisely.highlight_springmvc4.web.ch4_5;import java.util.Random;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controllerpublic class SseController { @RequestMapping(value="/push",produces="text/event-stream") //1 使用输出的媒体类型为text/event-stream,这是服务器端SSE的支持, //本例演示每5秒钟向浏览器推送随机消息 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"; }}
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%@ 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>SSE Demo</title></head><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) { //1EventSource对象只有新式的浏览器才有,EventSource是SSE的客户端 var source = new EventSource('push'); s=''; source.addEventListener('message', function(e) { //2添加SSE客户端监听,在此获得服务器端推送的消息。 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></html>
2.Servlet 3.0 + 异步方法处理
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx)); //3注册Spring MVC的DispatcherServlet servlet.addMapping("/"); servlet.setLoadOnStartup(1); servlet.setAsyncSupported(true);//1开启异步方法处理
package com.wisely.highlight_springmvc4.web.ch4_5;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.context.request.async.DeferredResult;import com.wisely.highlight_springmvc4.service.PushService;@Controller//异步任务的实现是通过控制器从另外一个线程返回一个Deferred,这里的DeferredResult是从pushService中获得的public class AysncController { @Autowired PushService pushService; //1定时任务,定时更新DeferredResult @RequestMapping("/defer") @ResponseBody public DeferredResult<String> deferredCall() { //2返回给客户端DeferredResult return pushService.getAsyncUpdate(); }}
package com.wisely.highlight_springmvc4.service;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Service;import org.springframework.web.context.request.async.DeferredResult;@Servicepublic 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()); } }}
<script type="text/javascript"> deferred();//1 function deferred(){ $.get('defer',function(data){ console.log(data); //2 deferred(); //3 }); }</script>
4.6 Spring MVC的测试
4.6.1 点睛
为了测试Web项通常不需要启动该项目,我们需要一些Servlet相关的模拟对象。
在Spring里,我们使用@WebAppConfiguration指定加载的ApplicationContext是一个WebApplicationContext。
测试驱动开发(TDD),我们按照需求先写一个自己预期结果的测试用例,这个测试用例刚开始肯定是失败的测试,随着不断的编码和重构,最终让测试用例通过测试,这样才能保证软件的质量和可控性。
4.6.2 示例
package com.wisely.highlight_springmvc4.web.ch4_6;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import com.wisely.highlight_springmvc4.service.DemoService;@Controllerpublic class NormalController { @Autowired DemoService demoService; @RequestMapping("/normal") public String testPage(Model model){ model.addAttribute("msg", demoService.saySomething()); return "page"; }}
package com.wisely.highlight_springmvc4.web.ch4_6;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;import com.wisely.highlight_springmvc4.service.DemoService;@RestControllerpublic class MyRestController { @Autowired DemoService demoService; @RequestMapping(value = "/testRest" ,produces="text/plain;charset=UTF-8") public @ResponseBody String testRest(){ return demoService.saySomething(); }}
package com.wisely.highlight_springmvc4.web.ch4_6;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.mock.web.MockHttpServletRequest;import org.springframework.mock.web.MockHttpSession;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import org.springframework.test.context.web.WebAppConfiguration;import org.springframework.test.web.servlet.MockMvc;import org.springframework.test.web.servlet.setup.MockMvcBuilders;import org.springframework.web.context.WebApplicationContext;import com.wisely.highlight_springmvc4.MyMvcConfig;import com.wisely.highlight_springmvc4.service.DemoService;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = {MyMvcConfig.class})@WebAppConfiguration("src/main/resources") //1 @WebAppConfiguration注解在类上,用来声明加载的ApplicationContext是一个WebApplicationContext。//它的属性指定的是Web资源的位置。public class TestControllerIntegrationTests { private MockMvc mockMvc; //2模拟MVC对象 @Autowired private DemoService demoService;//3 @Autowired WebApplicationContext wac; //4 可注入WebApplicationContext @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 模拟向/normal进行get请求 .andExpect(status().isOk())//9 预期控制返回状态为200 .andExpect(view().name("page"))//10 预期view的名称为page .andExpect(forwardedUrl("/WEB-INF/classes/views/page.jsp")) //11预期页面转向的真正路径为/WEB-INF/classes/veiws/page.jsp .andExpect(model().attribute("msg", demoService.saySomething())); //12 预期model里的值是demoService.saySomething()返回值hello。 } @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 预期返回值的内容为demoService.saySomething()返回值hello }}
- 第4章 Spring MVC基础
- Beginning Spring学习笔记——第3章(一)Spring MVC基础
- Spring实战(第4版) Spring Inaction 笔记(第五章)Spring MVC
- 第22章 Spring基础
- 第1章 Spring基础
- spring mvc 基础笔记
- spring MVC 基础
- spring mvc 基础
- spring mvc 基础配置
- Spring MVC基础
- Spring MVC基础
- Spring MVC基础
- Spring MVC-----基础注解
- Spring MVC基础
- Spring MVC----基础
- Spring MVC基础
- Spring MVC基础入门
- [Spring MVC] 入门基础
- volatile与synchronized
- ogre 引擎 框架追踪 第六章 渲染流程
- opencv环境搭建(linux)
- [leetcode] 421. Maximum XOR of Two Numbers in an Array 解题报告
- Android开发人员不得不收集的代码
- 第4章 Spring MVC基础
- web安全————XSS(预防篇)
- 四元数初学
- mysql查询出现ambiguous的问题
- kafka的解析
- iOS之Reachability和AFN实时检测网络状态
- Win7下合并U盘分区
- 共享内存循环形队列池设计
- Eclipse安装Pydev的插件搭建Python环境