第5章 构建Spring Web应用程序


1、SpringMVC请求:
请求---->DispatcherServlet(请求的第一站,前端控制器,将请求委托给其他应用程序来处理)
DispatcherServlet---->相应的控制器(通过查询处理器映射器来查询到底传递给那个控制器)
控制器--(模型和视图名)-->DispatcherServlet---->视图解析器--(视图)-->相应
2、配置DispatcherServlet
1:传统的方法是讲DispatcherServlet配置在web.xml中。
2:这里我们将DispatcherServlet配置在Servlet中。
这种方法是传统的xml配置的替代,但是需要部署在支持Spring3.0的Web容器中。(Tomcat7或者更高)
/**
        DispatcherServlet启动会引起Spring应用上下文的创建,应用上下文加载Web组件的bean(控制器、视图解析器、处理器)
        ContextLoaderListener的创建会加载其他bean(后端中间层、数据层的bean)
        AbstractAnnotationConfigDispatcherServletInitializer会同时创建 DispatcherServlet和ContextLoaderListener。
        getServletClasses()用于指定Spring应用上下文的bean的文件(包含@Configuration注解的java类)
        getRootConfigClasses()用于指定ContextLoaderListener创建的上下文加载的bean的配置文件(包含@Configuration注解的java类)
        */
        public class SpitterWebAppInitializer extends  AbstractAnnotationConfigDispatcherServletInitializer{
            @Override
            protected String[] getServletMappings(){
                return new String[]{"/"};       //将DispatcherServlet映射到“/”,将会处理应用的所有请求。
            }
            //用来指定ContextLoaderListener上下文中需要加载的bean的配置文件。
            @Override
            protected Class<?>[] getRootConfigClasses(){
                return new Class<?>[] {RootConfig.class};
            }
            //DispatcherServlet启动的时候会创建Spring应用上下文。并加载bean。此处要求加载定义在WebConfig中的bean。
            @Override
            protected Class<?>[] getServletConfigClasses(){
                return new Class<?>[] {WebConfig.class};
            }
        }
3、启用Spring MVC
1:使用xml配置:
 <mvc:annotation-driven>
    2:使用java文件配置(@EnableWebMVC注解)
注意如果只加@EnableWebMVC注解,这个配置文件不会配置视图解析器、没有启动组件扫描、等功能缺陷。
解决上述问题的配置:
@Configuration
        @EnableWebMvc       //启用SpringMVC
        @ComponentScan("spitter.web")
        public class WebConfig extends WebMvcConfigurerAdapter{
            @Bean
            public ViewResolver viewResolver(){     //配置jsp视图解析器
                InternalResourceViewResolver resolver = new InternalResourceViewResolver();
                resolver.setPrefix("/WEB-INF/views/");
                resolver.setSuffix(".jsp");
                resolver.setExposeContextBeansAsAttributes(true);
                return resolver;
            }
            //配置静态资源处理(要求DispatcherServlet对静态资源的请求转发到Servlet容器中默认的Servlet上,而不是DispatcherServlet类来处理)
            @Override
            public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
                configurer.enable();
            }
        }
      Spring应用上下文的已近随着DispatcherServlet的创建而创建了。接下来配置RootConfig。
      @Configuration
      @ComponentScan(basePackage={"spitter"},excludeFilters = {@Filter(type=FilterType.ANNOTATION,value=EnableWebMvc.class)})
      public class RootConfig{}
4、编写基本的控制器
例如:
   @Controller         //声明控制器
    public class HomeController{
        @RequestMapping(value="/",method = RequestMethod.GET)   //匹配“/”的GET请求
        public String home(){
            return "home";  //返回视图名(结合视图解析器:视图为:/WEB-INF/views/home.jsp)
        }
    }
5、定义类级别的请求处理
例如:
        @Controller
        @RequestMapping("/")
        public class HomeController{
            @RequestMapping(method = RequestMethod.GET)     //这个方法匹配的依然是"/"的GET请求。只不过将匹配路径的"/"放到了类级别。
            public String home(){
                return "home";
            }
        }    
        //匹配多个路径
        @controller
        @RequestMapping("/","/homepage")        //可以同时匹配"/"和"/homepage"
        public class HomeController{...}
6、传递模型数据到视图中(返回视图的同时给视图传递模型)
1:首先我们定义一个用于访问数据的Repository:
        public interface SpittleRepository{
            List<Spittle> findSpittles(long max, int count);
        }
    2:编写控制器
        @Controller
        @RequestMapping("/spittles")
        public class SpittleController{
            private SpittleRepository spittleRepository;
            @Autowired
            public SpittleController(SpittleRepository spittleRepository){      //构造器中传入用于访问数据的属性
                this.spittleRepository = spittleRepository;
            }
            @RequestMapping(method = RequestMethod.GET)
            public String spittles(Model model){        //Model其实就是一个Map,它会被传递给视图。
                model.addAttribute(spittleRepository.findSpittles(Long.MAX , 20));  //没有写key,会根据类型自动判断,这里判断为spittleList。
                //也可以明确key
                //model.addAttribute("spittleList",spittleRepository.findSpittles(Long.MAX , 20));
                return "spittles";
            }
        }
        //使用Map类型封装数据:
例如:
        @RequestMapping(method = RequestMethod.GET)
        public String spittles(Map model){
            model.put("spittleList",spittleRepository.findSpittles(Long.MAX , 20));
            return "spittles";
        }
        //不写key不写返回视图的方法
        @RequestMapping(method = RequestMethod.GET)
        public List<Spittle> spittles(){
            return spittleList",spittleRepository.findSpittles(Long.MAX , 20);
        }
        //key:根据类型推断为:spittleList
        //视图名:因为这个方法匹配"/spittles",所以视图名为spittles。
7、接收请求的输入
SpringMVC从客户端中获取属性的方法:
查询参数、表单参数、路径参数。
7.1:处理查询参数:
//实现翻页功能,需要传入两个值,max、count。
            @RequestMapping(method = RequestMethod.GET)
            public List<Spittle> spittles(@RequestParam("max") long max , @RequestParam("count") int count){
                return spittleRepository.findSpittles(max , count);
            }
        //设点参数的默认值
            @RequestMapping(method = RequestMethod.GET)
            public List<Spittle> spittles(
                @RequestParam(value = "max" , defaultValue = MAX_LONG_AS_STRING) long max ,
                @RequestParam(value = "count" , defaultValue = 10) int count
                ){
                return spittleRepository.findSpittles(max , count);
            }
   7.2:通过路径参数接收输入:
场景:我们需要一个名为SpittleID的参数查询指定的某一条记录:
            /**
            通过参数查询:
            下面这个类中的showPaittle方法将配“/spittles/show?spittle_id”的GET请求。(/spittles/show?spittle_id=123445)
            */
            @Controller
            @RequestMapping("/spittles")
            public class SpittleController{
                @RequestMapping(value = "/show" , method = RequestMethod.GET)
                public String showPaittle(
                    @RequestParam("spittle_id" long spittleId),
                    Model model
                ){
                    model.addAttribute("key" , spittleRepository.findSpittles(spittleId));
                    return "spittle";
                }
            }
            /**
            通过URL路径标识
            下面的方法可以匹配“/spittles/spittleId”URL路径(/spittles/234423)
            */
            @Controller
            @RequestMapping("/spittles")
            public class SpittleController{
                @RequestMapping(value = "/{spittleId}" , method = RequestMethod.GET)        //{}为占位符
                public String spittle(@PathVariable("spittleId") Long spittleId , Model model){ //无论占位符部分的值是什么都会传到处理方法中。
                    model.addAttribute("key" , spittleRepository.findSpittles(spittleId));
                    return "spittle";
                }
            }
            //@PathVariable("spittleId" Long spittleId , Model model)由于方法参数名和占位符一直所以可以胜率为:
            //@PathVariable(Long spittleId , Model model)
            //如果@PathVariable中的Value属性没有的话,会假设方法参数名称和路径占位符名称相同。
8、处理表单
例如表单:
        <html>
            <head>
                <title>Spittr</title>
            </head>
            <body>
                <form>
                    First Name: <input type = "text" name firstName="firstName" />
                    Last Name : <input type = "text" name LastName = "lastName" />
                    UserName  : <input type = "text" name UserName = "userName" />
                    PassWord  : <input type = "password" name = "password" />
                    <input type = "submit" value = "Register">
                </form>
            </body>
        </html>
    控制器:
        @Controller
        @RequestMapping("/spitter")
        public class SpitterController{
            private SpitterRepository spitterRepository;
            @Autowired
            public SpitterController(SpitterRepository spitterRepository){      //SpitterRepository是DAO层的类
                this.spitterRepository = spitterRepository;
            }
            @RequestMapping(value = "/register" , method = GET)     //这个请求用于跳转到注册页面
            public String showRegisterFrom(){
                return "register"
            }
            @RequestMapping(value = "/register" , method = POST)
            public String processRegister(Spitter spitter){
                spitterRepository.save(spitter);        //Spitter类中的属性对应了表单中的属性。按照名称匹配。
                return "redirect:/spitter/"+spitter.getUserName;    //重定向到别的页面。(redirect:会被解析为重定向。forward:是跳转)
            }
        }
    处理重定向的控制器:
        @RequestMapping(value ="/{username}" , method = GET)
        public String ShowSpitterProfile(@PathVariable String userName , Model model){
            Spitter spitter = spitterRepository.findByUserName(userName);
            model.addAttribute(spitter);
            return "profile";
        }
    表单验证:
(表单中,填写的数据为空、数据太长等异常情况需要解决)
1、一种比较初级的方法是,在控制其中添加一些校验代码。(校验代码污染了控制器)
2、利用Spring对java校验API(JSR-303)的支持。(只需要在类路径下包含实现了Java校验API的类即可)
java校验API提供的校验注解(只需放在属性上就可以限制属性的值,这些注解位于 javax.validation.constraints):
注  解 描  述
@AssertFalse 所注解的元素必须是 Boolean 类型,并且值为false
@AssertTrue 所注解的元素必须是 Boolean 类型,并且值为true
@DecimalMax 所注解的元素必须是数字,并且它的值要小于或等于给定的BigDecimalString值
@DecimalMin 所注解的元素必须是数字,并且它的值要大于或等于给定的BigDecimalString值
@Digits 所注解的元素必须是数字,并且它的值必须有指定的位数
@Future 所注解的元素的值必须是一个将来的日期
@Max 所注解的元素必须是数字,并且它的值要小于或等于给定的值
@Min 所注解的元素必须是数字,并且它的值要大于或等于给定的值
@NotNull 所注解元素的值必须不能为null
@Null 所注解元素的值必须为null
@Past 所注解的元素的值必须是一个已过去的日期
@Pattern 所注解的元素的值必须匹配给定的正则表达式
@Size 所注解的元素的值必须是String、集合或数组,并且它的长度要符合给定的范围
在我们例子中只需要在Spittle类的属性上添加@NotNull和@Size注解即可
1:添加校验注解
                    public class Spittle{
                        private Long id;
                        @NotNull
                        @Size(min = 5 , max = 6)
                        private String userName;
                        @NotNull
                        @Size(min = 5 , max = 6)
                        private String passWord;
                        @NotNull
                        @Size(min = 5 , max = 6)
                        private String firstName;
                        @NotNull
                        @Size(min = 5 , max = 6)
                        private String lastName;
                    }
                2:启用校验功能(修改接收数据的控制器)
                    @RequestMapping(value = "/register" , method = POST)
                    public String processRegister(@Valid Spitter spitter , Errors errors){      //校验Spitter输入
                        if(errors.hasErrors){
                            return "registerForm"   //校验不通过,返回到注册页面
                        }
                        spitterRepository.save(spitter);
                        return "redirect:/spitter/"+spitter.getUserName;
                    }






原文地址:https://www.cnblogs.com/Xmingzi/p/8926413.html