zoukankan      html  css  js  c++  java
  • java——SpringBoot(3)

    通过增删改查案例了解SpringBoot各种功能;

    为了增加Mvc功能,我们会经常覆写 extends WebMvcConfigurationSupport、implements WebMvcConfigurer接口,需要注意的是: extends WebMvcConfigurationSupport将会覆盖原本的自动装配,即需要自己补充覆写所需要的功能,如访问静态文件等等,加上目前接口已有默认的方法了,所以建议还是直接implements WebMvcConfigurer接口,这样我们只需要覆写所增加的方法即可;而@EnableWebMvc实际上是引入一个DelegatingWebMvcConfiguration,而DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport,因此SpringBoot2.0版本不可再@EnableWebMvc,以上就是刚接触SpringBoot2.0所踩的坑;

    进入主题首先我们可以覆写addViewControllers来简化访问对应的页面:

    @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/login").setViewName("login");
            
        }

    对页面进行国际化管理:

    在resources下编写装换配置文件:

     修改html文件,进行绑定:

     SpringBoot自动配置好了管理国际化资源文件的组件;

    国际化Locale(区域信息对象);LocaleResolver(获取区域信息对象);

    覆写其方法返回类:

    public class MyLocaleResolver implements LocaleResolver {
    
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            // TODO Auto-generated method stub
            Locale locale = Locale.getDefault();
            String l = request.getParameter("l");
            if(!StringUtils.isEmpty(l)) {
                String[] split = l.split("_");
                locale = new Locale(split[0],split[1]);
            }
            return locale;
        }
    
        @Override
        public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
            // TODO Auto-generated method stub
            
        }
        
    }

    要记得将修改类注入容器中:

    public class MyMvcConfig extends WebMvcConfigurationSupport{
        @Bean
        public LocaleResolver localeResolver() {
            return new MyLocaleResolver();
        }

    登录检验:

    编写控制器:

    @Controller
    public class LoginController {
        @PostMapping(value = "/user/login")
        //@RequestMapping(value="/user/login",method = RequestMethod.POST)
        public String login(@RequestParam("username") String username,@RequestParam("password") String password,
                            Map<String,Object> map,HttpSession session) {
            if(!StringUtils.isEmpty(username) && "123456".equals(password)) {
                session.setAttribute("loginUser",username);
                return "redirect:/main.html";
            }else {
                map.put("msg","用户名密码错误");
                return "login";
            }
            
        }
    }

    这里的/main.html会映射到首页里;redirect:作用就是将返回变成一个访问路径/main.html而不是一个字符串;

    对其他页面进行登录限制:

    编写拦截器:

    public class LoginHandlerIntercep implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            // TODO Auto-generated method stub
            Object user = request.getSession().getAttribute("loginUser");
            if(user == null) {
                request.setAttribute("msg", "未登录请先登录");
                request.getRequestDispatcher("/login").forward(request, response);
                return false;
            }else {
                return true;
            }
            
            
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            // TODO Auto-generated method stub
            HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            // TODO Auto-generated method stub
            HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
        }
        
    }

    增加 拦截器并避免拦截静态资源:

    @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            // TODO Auto-generated method stub
            //super.addInterceptors(registry);
            registry.addInterceptor(new LoginHandlerIntercep()).addPathPatterns("/**").excludePathPatterns("/login","/user/login","/","/css/**","/js/**","/img/**");
        }

    编写逻辑功能:

    目录结构:

     查询:

    添加:先来到添加页面,按提交键进行提交:

     修改:先来到修改页面:,按修改键进行修改:

     删除:删除也是post,相当于提交一次表单,为了避免每次删除都要编写一个<form>标签,我们可以把标签写在外面,通过js进行调用,页面的所有删除都调用这个表单就好:

     

     

     在编写html页面需要注意的是:如果我们将增加和修改页面共用一页面的话,也就是add.html和change.heml共用,但需要他们的回显不能一样,增加页面回显的是默认的样例,而修改页面回显的是所选修改id对应的属性值:

     这样如果emp有值的话说明调用的是修改页面,因为修改页面我们有返回一个emp对象,而增加页面是没有的;

     控制类编写:

    @Controller
    public class EmployeeController {
        @Autowired
        DepartmentDao departmentDao;
        @Autowired
        EmployeeDao employeeDao;
        @GetMapping("/emps")
        public String list(Model model) {
            Collection<Employee> employees = employeeDao.getAll();
            model.addAttribute("emps", employees);
            return "emp/list";
        }
        @GetMapping("/emp")
        public String toAddPage(Model model) {
            Collection<Department> departments = departmentDao.getDepartments();
            model.addAttribute("depts", departments);
            return "emp/add";
        }
        @PostMapping("/emp")
        public String Addemp(Employee employee) {
            System.out.println(employee);
            employeeDao.save(employee);
            return "redirect:/emps";
        }
        
        @GetMapping("/emp/{id}")
        public String changePage(@PathVariable("id") Integer id, Model model) {
            Employee employee = employeeDao.get(id);
            model.addAttribute("emp", employee);
            Collection<Department> departments = departmentDao.getDepartments();
            model.addAttribute("depts", departments);
            return "emp/change";
        }
        @PutMapping("/emp")
        public String update(Employee employee) {
            employeeDao.save(employee);
            return "redirect:/emps";
        }
        @DeleteMapping("/emp/{id}")
        public String delete(@PathVariable("id") Integer id) {
            employeeDao.delete(id);
            return "redirect:/emps";
        }
    }

    错误处理机制:

    可以参照ErrorMvcAutoConfiguration;

    这个配置类加入了以下组件:

     

     DefaultErrorAttributes:定制错误页面的共享信息;、BasicErrorController:处理默认/error请求(这里会根据请求的来源进行区分,如果是网页的会产生html类型数据返回,如果是客户端会返回json数据);

    ErrorPageCustomizer:会产生/error(默认)请求然后交给BasicErrorController;DefaultErrorViewResolver:具体去到哪个页面,如error/4xx.html或者error/5xx.html

    错误处理的自动配置;一但系统出现4xx或者5xx之类的错误;ErrorPageCustomizer就会生效(定制错误的响应规则);就会来到/error请求;就会被BasicErrorController处理;去哪个页面是由DefaultErrorViewResolver解析得到的;

    因此我们如果只想改其网页显示只需在resources下建个errou目录然后创建4xx.html或者5xx.html即可;

    自制错误页面:

    首先设置好访问抛出异常路径:

    @ResponseBody
        @RequestMapping("/hello")
        public String hello(@RequestParam("user") String user) {
            if(user.equals("aaa")) {
            throw new UserNotException();
        }else {
            return "hahahaha";
        }
        }

    再来自定义UserNotException()类:

    public class UserNotException extends RuntimeException {
        public UserNotException() {
            super("用户不存在");
        }
    }

    创建ExceptionHangder类处理controller类抛出的异常:

    @ControllerAdvice
    public class MyExceptionHandler {
        /***@ResponseBody
        @ExceptionHandler(UserNotException.class)
        public Map<String,Object> handleException(Exception e) {
            Map<String,Object> map = new HashMap();
            map.put("code","user.notexist");
            map.put("message",e.getMessage());
            return map;
        }***/
        @ExceptionHandler(UserNotException.class)
        public String handleException(Exception e,HttpServletRequest request) {
            Map<String,Object> map = new HashMap();
            request.setAttribute("javax.servlet.error.status_code", 401);
            map.put("code","user.notexist");
            map.put("message",e.getMessage());
            return "forward:/error";
        
    }
    }

    此时我们访问/hello?user=aaa时就会抛出自定义好的异常,转到error/401.html页面上;

    这里如果使用html静态页面:在resources/public/error/ 下定义;

    如果使用模板引擎页面:在templates/error/下定义;

    templates/error/ 这个的优先级比较 resources/public/error/高;

    将我们的定制数据携带出去:

    来编写一个ErrorController的实现类【或者是编写AbstractErrorController的子类】,放在容器中;
    页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getErrorAttributes得到;
    容器中DefaultErrorAttributes.getErrorAttributes();默认进行数据处理的;

    @Component
    public class MyErrorAttributes extends DefaultErrorAttributes {
        @Override
        public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
    boolean includeStackTrace) {
            Map<String, Object> map = super.getErrorAttributes(requestAttributes,
    includeStackTrace);
            map.put("company","atguigu");
            return map;
        }
    }

    配置嵌入式Servlet容器:

    由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文
    件。
    注册三大组件用以下方式:

    过滤器:

    public class MyFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // TODO Auto-generated method stub
            Filter.super.init(filterConfig);
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            // TODO Auto-generated method stub
            System.out.println("MyFilter");
            chain.doFilter(request, response);
        }
    
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
            Filter.super.destroy();
        }
        
    }

    监听器:

    public class MyListener implements  ServletContextListener{
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            // TODO Auto-generated method stub
            System.out.println("Listener开启");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            // TODO Auto-generated method stub
            System.out.println("Listener关闭");
        }
    }

    Servlet:

    public class MyServlet extends HttpServlet{
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // TODO Auto-generated method stub
            doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // TODO Auto-generated method stub
            resp.getWriter().write("Hello MyServlet!");
        }
        
    }

    将这3大组件分别注入:

    @Configuration
    public class MyServletConfig {
        @Bean
        public ServletRegistrationBean myServlets() {
            ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet"); 
            return servletRegistrationBean;
        }
        @Bean
        public FilterRegistrationBean myFilter() {
            FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean();
            filterRegistrationBean.setFilter(new MyFilter());
            filterRegistrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
            return filterRegistrationBean;
        }
        @Bean
        public ServletListenerRegistrationBean myListener() {
            ServletListenerRegistrationBean servletListenerRegistrationBean=new ServletListenerRegistrationBean(new MyListener());
            return servletListenerRegistrationBean;
        }
        
    }

    SpringBoot帮我们自动SpringMVC的时候,自动的注册SpringMVC的前端控制器;DIspatcherServlet;
    DispatcherServletAutoConfiguration中:

    @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    @ConditionalOnBean(value = DispatcherServlet.class, name =
    DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public ServletRegistrationBean dispatcherServletRegistration(
          DispatcherServlet dispatcherServlet) {
       ServletRegistrationBean registration new ServletRegistrationBean(
             dispatcherServlet, this.serverProperties.getServletMapping());
        //默认拦截: /  所有请求;包静态资源,但是不拦截jsp请求;   /*会拦截jsp
        //可以通过server.servletPath来修改SpringMVC前端控制器默认拦截的请求路径
       
       registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
       registration.setLoadOnStartup(
             this.webMvcProperties.getServlet().getLoadOnStartup());
       if (this.multipartConfig != null) {
          registration.setMultipartConfig(this.multipartConfig);
       }
       return registration;
    }

    替代为其他的Servlet容器:

    tomcat为默认使用,在pom.xml文件中引入web模块默认就是使用嵌入式的Tomcat作为Servlet容器;

    引入Jetty:

    <!‐‐ 引入web模块 ‐‐>
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring‐boot‐starter‐web</artifactId>
       <exclusions>
          <exclusion>
             <artifactId>spring‐boot‐starter‐tomcat</artifactId>
             <groupId>org.springframework.boot</groupId>
          </exclusion>
       </exclusions>
    </dependency>
    <!‐‐引入其他的Servlet容器‐‐>
    <dependency>
       <artifactId>spring‐boot‐starter‐jetty</artifactId>
       <groupId>org.springframework.boot</groupId>
    </dependency>

    引入Undertow是同样的道理;

    对于想改容器默认配置的有两种方法:一种是在配置文件通过属性server.xxx或server.tomcatxxx来修改;

    另一种是实现实现WebServerFactoryCustomizer接口,重写它的customize()方法,对容器进行定制配置:

    /***@Bean
        public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
            return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
                @Override
                public void customize(ConfigurableWebServerFactory factory) {
                    factory.setPort(8081);
                }
            };
        }***/

    至于原理可看下面网站,该内容还是比较重要的,不可忽略;

    嵌入式Servlet容器的自动装配原理:

    可参考网站:https://www.jianshu.com/p/017a7f40efff

    外置的Servlet容器:外面安装Tomcat---应用war包的方式打包;
    步骤
    1)、必须创建一个war项目;(利用idea创建好目录结构)
    2)、将嵌入式的Tomcat指定为provided;

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring‐boot‐starter‐tomcat</artifactId>
       <scope>provided</scope>
    </dependency>

    3)、必须编写一个SpringBootServletInitializer的子类,并调用configure方法

    public class ServletInitializer extends SpringBootServletInitializer {
       @Override
       protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
           //传入SpringBoot应用的主程序
          return application.sources(SpringBoot04WebJspApplication.class);
       }
    }

    4)、启动服务器就可以使用;

  • 相关阅读:
    nodejs生成UID(唯一标识符)——node-uuid模块
    python 3.6 关于python的介绍
    Hdu-3333 Turning Tree (离线树状数组/线段树)
    HDU-3333 Turing Tree 分块求区间不同数和
    Hello,World.
    IntelliJ IDEA 自动化工具安装并添加自动化测试框架
    git&sourcetree安装及在IntelliIJ下拉取项目基础使用
    3.jquery在js文件中获取选择器对象
    2.jquery在js中写标准的ajax请求
    操作系统简介
  • 原文地址:https://www.cnblogs.com/lzj-learn/p/13132164.html
Copyright © 2011-2022 走看看