zoukankan      html  css  js  c++  java
  • 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流程图

  • 相关阅读:
    从应用到平台,云服务架构的演进过程
    从应用到平台,云服务架构的演进过程
    武汉小猫科技-工作总结(1):一图胜万言
    武汉小猫科技-工作总结(1):一图胜万言
    一个App带你学会Retrofit2.0,麻麻再也不用担心我的网络请求了!
    关于创业公司产品开发原则
    关于创业公司产品开发原则
    【Deep learning book】
    【NLP】word2vec
    【python】好书
  • 原文地址:https://www.cnblogs.com/YC-L/p/14258436.html
Copyright © 2011-2022 走看看