SpringMVC介绍

什么是MVC

 

 最典型的MVC就是JSP+servlet+JavaBean的模式

 

 Spring-web

 SpringMVC

 

public class MyServlet extends HttpServlet{

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        String username = req.getParameter("username");
        req.getSession().setAttribute("username", username);
        req.getRequestDispatcher("index.jsp").forward(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{        
        this.doPost(req. resp);
    }    
}

 web.xml配置servlet

 

 

 springmvc.xml   

 

 idea,添加lib文件夹

public class HelloController{
    public void hello(){
        System.out.println(this.getClass().getName());
    }

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception{

        // 创建对象
        ModelAndView mv = new ModelAndView();
        // 添加视图名称, 要跳转的页面名称
        mv.setViewName("hello");
        // 向前端页面添加属性值
        mv.addObject("hello", "hello, springmvc");
        return null;
    }
}

Spring的处理过程

@Controller
public class HelloController{

    @RequestMapping("/hello")
    public String hello(){
        map.put("hello", "hello,SpringMVC");
        return "hello";
    }

    @RequestMapping("/hello")
    public String hello2(Map<String, String> map){
        map.put("hello", "hello, SpringMVC");
        return "hello";
    }

    @RequestMapping(value = "/hello", method = RequestMethod.POST)
    public String hello2(Map<String, String> map){
        map.put("hello", "hello, SpringMVC");
        return "hello";
    }

    @RequestMapping(value = "/hello", param = {"username"})
    public String hello2(Map<String, String> map){
        map.put("hello", "hello, SpringMVC");
        return "hello";
    }

    @RequestMapping(value = "/hello", param = {"username=zs", "age"})
    public String hello2(Map<String, String> map){
        map.put("hello", "hello, SpringMVC");
        return "hello";
    }

    // headers 表示限制请求头中的相关属性值, 用来做请求的限制
    @RequestMapping(value = "/hello", headers = {"User-Agent=..."})
    public String hello2(Map<String, String> map){
        map.put("hello", "hello, SpringMVC");
        return "hello";
    }
    // produces: 限制请求中的Content-Type
    // consumers: 限制响应中的Content-Type
    // @RequestMapping可以进行模糊匹配
    // ?:  替代任意一个人字符
    // *:  提供多个字符
    // **: 替代多层路径
}

常用的注解

参数列表

@Controller
public class PathVariableController{
    @RequestMapping("/testPathVariable/{name}")
    public String testPathVariable(@PathVariable String name){// rest方式用的比较多
        request.getParameter("name");
        System.out.println(name);
        return "hello";
    }
}

@Controller
public class PathVariableController{
    @RequestMapping("/testPathVariable/{id}")
    public String testPathVariable(@PathVariable("id") String name){// rest方式用的比较多
        request.getParameter("name");
        System.out.println(name);
        return "hello";
    }
}

@Controller
public class PathVariableController{
    @RequestMapping("/testPathVariable/{id}")
    public String testPathVariable(@PathVariable("id") Integer id, @PathVariable("name") String name){// rest方式用的比较多
        request.getParameter("name");
        System.out.println(name);
        return "hello";
    }
}

web.xml

springmvc.xml

 如果不使用rest,那么增删改查就需要建立四个接口,如果用rest那么用GET,POST,PUT,DELETE四个提交方式对应增删改查

public class UserDao{

    public void save(User user){
        System.out.println("save");
    }

    public void update(Integer id){
        System.out.println("update");

    }

    public void delete(Integer id){
        System.out.println("delete");
    }

    public void query(){
        System.out.println("query");
    }    
}

public class User{

}

@Controller
public class UserController{

    @Autowired
    private User userDao;

    @RequestMapping("/save")
    public String save(){        
        userDao.save(new User());
        return "success";
    }

    @RequestMapping("/update")
    public String update(Integer id){
        userDao.update(id);
        return "success";
    }

    @RequestMapping("/delete")
    public String delete(Integer id){
        userDao.delete(id);
        return "success";
    }

    @RequestMapping("/query")
    public String query(){
        userDao.query();
        return "success";
    }
}

 REST

  •  POST:创建              /user/1
  •  GET:获取                /user
  •  PUT:更新资源          /user/1
  •  DELETE:删除资源   /user/1

 导包

 

 web.xml 

 

 

public class UserDao{

    public void save(User user){
        System.out.println("save");
    }

    public void update(Integer id){
        System.out.println("update");

    }

    public void delete(Integer id){
        System.out.println("delete");
    }

    public void query(){
        System.out.println("query");
    }    
}

public class User{

}

@Controller
public class UserController{

    @Autowired
    private User userDao;

    @RequestMapping(value = "/user", method = RequestMethod.POST)
    public String save(){        
        userDao.save(new User());
        return "success";
    }

    @RequestMapping(value = "/user", method = RequestMethod.PUT)
    public String update(Integer id){
        userDao.update(id);
        return "success";
    }

    @RequestMapping(value = "/user", method = RequestMethod.DELETE)
    public String delete(Integer id){
        userDao.delete(id);
        return "success";
    }

    @RequestMapping(value = "/user", method = RequestMethod.GET)
    public String query(){
        userDao.query();
        return "success";
    }
}

public class MyFilter implements Filter{
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){
        filterChain.doFilter(servletRequest, servletResponse);
servletRequest.setCharacterEncoding("UTF-8");
servletResponse.setCharacterEncoding("UTF-8"); } }

 

 SpringMVC的使用

 

 RequestParam和PathVariable不要混淆

  •  RequestParam获取的是问号后面的键值对
  •  PathVariable获取的是路径后面的值

 RequestParam的参数

  • value:获取的参数值
  • required:表示当前属性值是否存在,默认值是true,如果没有,400,bad request
  • defaultValue:如果有传递参数就是用传递进来的参数,如果没有就是用默认值

 乱码问题解决

 需要设置过滤request和response的编码方式,可以自己手动编写过滤器,也可以由现成的框架实现

 post:分别设置request和response编码格式

 get:在tomcat的server.xml文件中,添加URIEncoding=utf-8

 调整顺序可以解决乱码问题

 

 在一个应用程序中,可能包含n多个过滤器,一般没有顺序要求,如果设置了编码过滤器,必须要将编码过滤器设置到最上面,保证编码过滤器,优先执行

 编码过滤器,要放在最上面的位置

 

@Controller
public class RequestController{
    @RequestMapping("/testRequest")
    public String testRequest(@RequestParam(value = "username", required = false) String name){
        System.out.println(name);
        return "success";
    }
}

// 获取请求头信息
@Controller
public class RequestController{

    @RequestMapping("/testRequest")
    public String testRequestHeader(@testRequestHeader String userAgent){
        System.out.println(userAgent);
        return "success";
    }

    // request.getCookie()
    @RequestMapping("/testCookie")
    public String testCookie(@CookieValue("JSESSIONID"), String jsid){
        System.out.println(jsid);
            return "success";
    }
}

@Controller
public class UserController22{
    @RequestMapping("/testUser")
    public String testUser(User user){
        System.out.println(user);
        return "success";
    }
}

每次tomcat可以启动,可以自己启动

 SessionAttribute

@Controller
@SessionAttributes(value = {"username", "msg"}, types = Integer.class) // 每次向request设置作品用于的时候, 顺带向session中保存一份
public class OutputController{

    @RequestMapping("/output")
    public String output(Map<String, String> map){
        map.put("msg", "hello,output");
        System.out.println(model.getClass());
        return "success";
    }

    @RequestMapping("/output1")
    public String output(Map<String, String> map){
        map.put("msg", "hello,output1");
        return "success";
    }

    @RequestMapping("/output2")
    public String output(Map<String, String> map){
        model.addAttribute("msg", "hello, output2");
        return "success";
    }

    @RequestMapping("/output3")
    public String output(Map<String, String> map){
        map.put("msg", "hello,output3");
        return "success";
    }

    @RequestMapping("/output4")
    public ModelAndView output(Map<String, String> map){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("success");
        mv.addObject("msg", "output4");
        return mv;
    }

    @RequestMapping("/testSession")
    public String testSession(Model model){
        model.addAtttibute("username", "zs");
        return "success";
    }
}

 被@ModelAttribute注释的方法会在此controller每个方法执行前被执行,因此对于一个controller映射多个URL的用法来说,要谨慎使用

@Controller
public class UserController{

    Object o1 = null;
    Object o2 = null;
    Model m1 = null;    


    @RequestMapping("update")
    public String update(@ModelAttribute("user2") User user, Model model){
        o2 = user;
        System.out.prinltn(user);
        System.out.println(o1 == o2);// true 指向同一个对象
        System.out.println(m1 == model);// false 
        return "success";
    }
    
    @ModelAttribute
    public void testModelAttribute(Model model){
        User user = new User();
        user.setId(1);
        user.setName("name");
        user.setPassword("1234");
        model.addAttribute("user2", user);
        o1 = user;
        m1 = model1;
    }
}    

SessionAttributes要注意,在使用的时候如果没有对应的值

@Controller
public class UserController{

    Object o1 = null;
    Object o2 = null;
    Model m1 = null;    


    @RequestMapping("update")
    public String update(@ModelAttribute("user2") User user, Model model){
        o2 = user;
        System.out.prinltn(user);
        System.out.println(o1 == o2);// true 指向同一个对象
        System.out.println(m1 == model);// false 
        return "success";
    }
    
    // 加一个user2标识, 可以匹配到user2
    @ModelAttribute("user2")
    public void testModelAttribute(Model model){
        User user = new User();
        user.setId(1);
        user.setName("name");
        user.setPassword("1234");
        model.addAttribute("user2", user);
        o1 = user;
        m1 = model1;
    }
}    

forward转发

  • 在使用转发的时候,要添加forward: 前缀
  • 可以实现多次转发请求,可以回到页面,也可以转发到其他页面请求中
@Controller
public class ForWardController{

    @RequestMapping("/forward")
    public String forward(){
        System.out.printfln("forward");
        return "forward:/index.jsp";
    }

    @RequestMapping("/forward2")
    public String forward2(){
        System.out.printfln("forward2");
        return "forward:/forward";
    }
}

redirct重定向

重定向操作也不会经过视图处理器

@Controller
public class Redirctontroller{

    @RequestMapping("/redirect")
    public String forward(){
        System.out.printfln("forward");
        return "redirect:/index.jsp";
    }

    @RequestMapping("/redirect2")
    public String forward2(){
        System.out.printfln("redirect2");
        return "redirect:/redirect";
    }
}

转发与重定向的区别

  • 转发是服务端
  • 重定向是客户端

 

  

 springmvc.xml

 默认的servlet处理类

 

 保证动态请求和静态资源能够访问

 

 自定义视图解析器

  •  InternalResourceViewResolver
public class MyViewResolver implements ViewResolver, Ordered{

    private int order = 0;


    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception{
        if(viewName.startsWith("test")){
            System.out.println(viewName);
            return MyView();
        }else{
            return null;    
        }        
    }
}

public void setOrder(int order){
    this.order = order;
}

@Override
public int getOrder(){
    return 0;
}

public class MyView implements View{
    @Override
    public String getContentType(){
        return null;
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception{
        System.out.println("model:" + model);
        PrintWriter writer = response.getWriter();
        writer.write("test");
        writer.write("gogogo");
    }
}

@Controller
public class ViewResolverController{

    @RequestMapping("/test")
    public String testView1(){
        System.out.println("testView");
        return "test:/index";
    }

    @RequestMapping("/test2")
    public String testView2(){
        System.out.println("testView");
        return "test2:/index";
    }
}

 springmvc.xml
 

 value的值越大,优先级越小

 添加自定义的类型转换器到ConversionServiceFactoryBean中

 

@Component
public class MyConverter implements Converter<String, User>{
    @Override
    public Object convert(Object source){
        User user = null;
        if(source != null && "".equals(source) && (source.split("-").length == 4)){
            user = new User();
            user.setId(Integer.parseInt(source.split("-")[0]));
            user.setName(source.split("-")[1]);
            user.setAge(Integer.parseInt(source.split("-")[2]));
            user.setPassword(source.split("-")[3]);
        }
        return null;
    }
}

// 自定义类型转换器的时候, 注意对应的属性值跟方法中参数值对应起来
@Controller
public class MyConverterController{

    @RequestMapping("/converter")
    public String testConverter(User user, Model model){
        System.out.println(user);
        model.addAttribute("user", user);
        return "success";
    }
}

 自定义日期转换器

 springmvc.xml

 

  • 如果需要添加日期格式化器,只需要在实体类上添加@DataTimeFormat("格式")即可
  • 如果配置日期格式化器的时候,同时配置了类型转换器,那么就会失效
  • 需要使用 FormattingConversionServiceFactoryBean 对象
// 如果使用默认的类型转换器, 那么在输入日期的时候使用/作为分隔
@Controller
public class DateConverterController{

    @RequestMapping("/testDateConverter")
    public String testDateConverter(User user){
        System.out.println(user);
        return "success";
    }
}

public class User{

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birth;
}

 数据校验

 JSR303提供的标准校验

 

 Hibernate Validator 扩展注解

 

 JSR校验框架

 

 导包

 

 日期格式化器

public class Person{
    @NouNull
    private Integer id;
    @Length(min = 3, max = 10)
    private String name;    
    private Integer age;
    private String gender;
    @Past // 设置的日期只能是之前的日期
    private Date birth;    
    @Email
    private String gmail;
}

@Controller
public class ValidationController{
    @RequestMapping("/validation")    
    public String validate(@Valid Person person, BindingResult){
        if(BindingResult.hasErrors()){
            System.out.println("验证失败");    
            // 获取到当前所有的错误
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            for(FieldError fieldError : fieldErrors){
                System.out.println(fieldError.getField());    
                System.out.println(fieldError.getDefaultMessage());    
                map.put(fieldError.getField(), fieldError.getDefaultMessage());    
            }
            model.addAttribute("errors", map);
            return "forward:/login.jsp";
        }else{
            System.out.println("登陆成功");    
            return "success";    
        }            
    }
}

 springmvc_json

 

 @RequestBody 表示把当前请求的内容

 @ResponseBody 解析字符串为标签

@Controller
public class JsonController{
    
    @ResponseBody
    @RequestMapping("/json")
    public String json(){
        List<User> list = new ArrayList<User>();
        list.add(new User("test1", 12, "man"));
        list.add(new User("test2", 13, "woman"));
        list.add(new User("test3", 14, "man"));
        return list;
    }

    @ResponseBody // 该注解会解析字符串为标签
    @RequestMapping("/json2")
    public String json2(){
        return "<h1>test</h1>";
    }

    @RequestMapping("/testRequestBody")    
    public String testRequestBody(@RequestBody String body){
        System.out.println(body);
        return "success";
    }

    @RequestMapping("/testRequestJson")
    public String testRequestJson(@RequestBody User user){
        System.out.println(user);
        return "success";
    }
}

public class User{
    private Integer id;
    private String name;
    private Integer age;
    private String gender;

    public User(){

    }

    public User(String name, Integer age, String gender){

    }
}

 自定义响应ResponseEntity

@Controller
public class Entity{
    @RequestMapping("test")
    public String test(HttpEntity<String> httpEntity){
        System.out.println(httpEntity);
        String body = httpEntity.getBody();
        return "success";
    }

    // 自定义响应相关的信息, 包含body和header
    @RequestMapping("testResponseEntity")
    public String teestResponseEntity(){
        String body = "<h1>gogogo</h1>";
        MultiValueMap<String, String> header = new HttpHeaders();
        header.add("set-cookie", "name=zs");
        return new ResponseEntity<String>(body, header, HttpStatus.OK);
    }
}

 servlet下载文件

@Controller
public class DownController{
    @RequestMapping("/download")
    public String download(HttpServletRequest request){
        // 获取下载路径
        ServletContext servletContext = request.getServletContext();
        servletContext.getRealPath("/scripts/...");
        // 通过io流对文件读写
        FileInputStream FileInputStream = new FileInputStream(realPath);
        byte[] bytes = new byte[FileInputStream.available()];
        FileInputStream.read(bytes);
        FileInputStream.close();
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.set("Content-Disposition", "attachment:filename=...");
        return new ResponseEntity<byte[]>(bytes, httpHeaders, HttpStatus.OK);
    }
}

 servlet上传文件

 

 springmvc.xml

 

 添加jar包

 

 多文件上传

@Controller
public class UploadController{

    @RequestMappin("upload")
    public String upload(@RequestParam("file") MultipartFile multipartFile, @RequestParam(value = "desc", required = false) String desc){
        System.out.println(desc);
        for(MultipartFile file: multipartFile){
            if(!file.isEmpty()){
                System.out.println(file.getOriginalFilename());
                multipartFile.transferTo(new File("d:\file\" + multipartFile.getOriginalFilename()));        
            }            
        }        
        return "success";
    }
}

 拦截器和过滤器的区别

 

 

  springmvc.xml

 

 执行顺序,preHandler->目标方法->postHandler->页面跳转->afterCompletion

 如果执行过程中抛出异常,那么afterCompletion依然会继续执行

 执行顺序

public class MyInterceptor implements HandlerInterceptor{

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response){
        System.out.println(this.getClass().getName());
        return true;// 返回指控制流程是否停止
    }

    public boolean postHandle(HttpServletRequest request, HttpServletResponse response){
        System.out.println(this.getClass().getName());
        return true;
    }

    public boolean afterCompletion(HttpServletRequest request, HttpServletResponse response){
        System.out.println(this.getClass().getName());
        return true;
    }
}

@Controller
public class InterceptorController{
    @RequestMapping("/testInterceptor")
    public String testInterceptor(){
        // 如果此处抛出异常, after依然会执行

        System.out.println(this.getClass().getName());
        return "success";
    }
}

 国际化

  login_en_US.properties

 

  login_zh_CN.properties

 

  jsp文件body内容

 

 

 springmvc.xml

 

 jsp文件的body标签前不要漏下以下配置

 

@Controller
public class I18nController{

    @Autowired
    private MessageSource messageSource

    @RequestMapping("/i18n")
    public String i18n(Locale locale){
        System.out.println(locale);
        String username = MessageSource.getMesssage("username", null, locale);
        System.out.println(username);
        return "login";
    }

    @RequestMapping("/i18n")
    public String i18n(@RequestParam("locale") String localStr, Locale locale, HttpSession session){
        Locale locale1 = null;
        System.out.println(locale);
        if(localStr != null && !"".equals(localStr)){
            locale1 = new Locale(localStr.split("_")[0], localStr.split("_")[1]);
        }else{
            locale1 = locale;
        }
        session.setAttribute(SessionLocaleResolver.class.getName() + ".LOCALE", locale1);
        return "login";
    }
}

public class MyLocaleResolver implements LocaleResolver{
    public Locale resolveLocale(HttpServletRequest request){
        Locale locale = null;
        String localeStr = request.getParameter("locale");
        if(localeStr != null && !"".equals(localStr)){
            locale = new Locale(localeStr.split("_")[0].localeStr.split("_"))
        }else{
            locale = request.getLocale();
        }
        return locale;
    }
}

 mvc异常处理机制

 容器启动好后,进入DispatcherServlet之后,会对HandlerExceptionResolver进行初始化操作

 可以通过@ControllerAdvice注解进行标注,表示为全局异常处理类

 如果有了全局异常,若当前类抛出了异常会现在本类查找,然后再查找全局异常

@Controller
public class ExceptionController{

    @RequestMapping("/exception1")
    public String exception(){
        System.out.println(this.getClass().getName());
        int i = 10/0;
        return "success";
    }

    @ExceptionHandler(value = ({ArithmeticExcepton.class, NullPointerException.class}))
    public String handlerException(Exception exception){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("error");
        mv.addObject("exce", exception);
        return mv;
    }

    @ExceptionHandler(value = (Exception.class))
    public String handlerException2(Exception exception){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("error");
        mv.addObject("exce", exception);
        return mv;
    }
}

@ControllerAdvice
public class MyGlobalExceptionHandler{

    @ExceptionHandler(value = ({ArithmeticExcepton.class, NullPointerException.class}))
    public String handlerException(Exception exception){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("error");
        mv.addObject("exce", exception);
        return mv;
    }

    @ExceptionHandler(value = (Exception.class))
    public String handlerException2(Exception exception){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("error");
        mv.addObject("exce", exception);
        return mv;
    }
}

 ResponseStatus

@Controller
public class ExceptionController{

    @ResponseStatus(reason = "", value = HttpStatus.NOT_ACCEPTABLE)
    @RequestMapping("/exception")
    public String handlerException(Exception exception){
        System.out.println("exception")
        return "success";
    }
}

 @ResponseStatus,可以标注在方法中,但是不推荐使用

@Controller
public class ExceptionController{

    @RequestMapping("/exception")
    public String handlerException(String username){
        System.out.println("exception")
        if("admin".equals(username)){
            return "success";
        }else{
            throw new UsernameException();
        }
        return "success";
    }
}

 Springmvc流程图

原文地址:https://www.cnblogs.com/YC-L/p/14258436.html