资讯专栏INFORMATION COLUMN

SpringMVC 配置和基本使用

CarterLi / 3296人阅读

摘要:配置开启注解模式简化配置自动注册默认提供了一系列的功能数据绑定数字和日期的转换的读写支持映射路径静态资源默认配置加入对静态资源的处理允许使用做整体配置映射后面的和类基本上都要自动包扫描,让认识然后就可以尽情的使用了。

花了点时间做的(比较水)笔记,有可能有漏洞,有不对的,欢迎指出(如果你会看的话)。

首先都是二话不说,先找依赖(Gradle):

// spring系列
// 这个jar文件包含Spring框架基本的核心工具类,Spring其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统中使用这些工具类。
compile group: "org.springframework", name: "spring-core", version: "4.2.5.RELEASE"
// 这个jar文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean以及进行Inversion of Control / Dependency Injection(IoC/DI)操作相关的所有类。
// 如果应用只需基本的IoC/DI支持,引入spring-core.jar及spring- beans.jar文件就可以了。
compile group: "org.springframework", name: "spring-beans", version: "4.2.5.RELEASE"
// 提供在基础IOC功能上的扩展服务,此外还提供许多企业级服务的支持,有邮件服务、任务调度、JNDI定位,EJB集成、远程访问、缓存以及多种视图层框架的支持。
compile group: "org.springframework", name: "spring-context", version: "4.2.5.RELEASE"
// 对JDBC 的简单封装
compile group: "org.springframework", name: "spring-jdbc", version: "4.2.5.RELEASE"
// 为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理
compile group: "org.springframework", name: "spring-tx", version: "4.2.5.RELEASE"
// 包含Web应用开发时,用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类、Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类
compile group: "org.springframework", name: "spring-web", version: "4.2.5.RELEASE"
// 这个jar文件包含Spring MVC框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、 XSLT相关类。
// REST Web服务和Web应用的视图控制器的实现, 当然,如果你的应用使用了独立的MVC框架,则无需这个JAR文件里的任何类。
compile group: "org.springframework", name: "spring-webmvc", version: "4.2.5.RELEASE"
// 对于单元测试和集成测试的简单封装
compile group: "org.springframework", name: "spring-test", version: "4.2.5.RELEASE"

// Spring提供的对AspectJ框架的整合
compile group: "org.springframework", name: "spring-aspects", version: "4.2.5.RELEASE"

然后SpringMVC主要还是要以来Servlet,所以需要进行配置web.xml(顺带配置一个过滤器,让SpringMVC所有操作都是UTF-8格式):


         
    
    
        encodingFilter
        org.springframework.web.filter.CharacterEncodingFilter
        
            encoding
            UTF-8
        
    
    
        encodingFilter
        /*
    

    
    
        springmvc
        org.springframework.web.servlet.DispatcherServlet
        
            
            contextConfigLocation
            classpath:spring/spring-*.xml
        
        1
    
    
        springmvc
        /
    

在此之前可以先了解一下这两个配置,基本上是必备的,帮我们做了很多事情。



    
    
    

    
    
    
    
    
    

然后就可以尽情的使用了。

自动属性装配
/**
 * 这里的属性自动装配,可以装配很多东西,比如Bean对象,还有普通的字符串,当用户请求中带有同名的参数时,会自动把结果赋值到上面。
 * 然后还可以使用原生的Servlet对象,Spring也会自动注入,支持:
 * HttpServletRequest
 * HttpServletResponse
 * HttpSession
 * Writer
 * Reader
 * Locale
 * InputStream
 * OutputStream
 * java.security.Principal
 * 其中Write(Reader)和OutputStream(InputStream)和在Servlet一样,不能同时使用
 **/
public BaseDTO doLogin(User user, @RequestParam(value = "login_token") String login_token, HttpServletResponse response) {
                                 
}
数据类型转换器

之所以Spring能够自动装配属性(传入的参数都是String,但是我们接收到的可以是Integer等类型),是因为Spring写好了一些默认的数据类型转换器,然而为了满足要求,我们也可以自定义转换器:
先写好一个类型转换器类:

// 这个类的作用是把String转换成Timestamp
public class JsMillisecondsToDate implements Converter {

    @Override
    public Timestamp convert(String source) {
        long millis = Long.parseLong(source);
        return new Timestamp(millis);
    }
}

然后在Spring文件中配置:





    
        
            
                
            
        
    

之后的话Spring就有了String -> Timestamp的支持,可以自动的将String装配成Timestamp的支持。

@RequestMapping(value = "/submitText", method = RequestMethod.POST)
@ResponseBody
public BaseDTO submitText(@RequestParam("title") String title, @RequestParam("date") Timestamp date, BindingResult bindingResult) {

    return null;    
}
// 传入的json可以是这样的(date是一个时间戳):{"title" : "初音未来的日常", "date", "122354864"}
// Spring会用我们定义的转换器去转换,如果转换出错了,会把错误结果放入BindingResult对象中,可以检查发生了什么问题。
自定义试图解析器


    
    
        

        
        
        
        
        
        
    

    
        
    

    
        
        
        

        
        
        
        
    

    
    
        
        
        

        
        
        
    

作用:

// 其实返回的html视图是/WEB-INF/html/welcome.html
@RequestMapping(value = {"/welcome.html", "/"}, method = RequestMethod.GET)
public String welcome() {
    return "html/welcome";
}
数据校验

使用jsr303标准,然后加入

// hibernate 数据校验框架
compile group: "org.hibernate", name: "hibernate-validator", version: "5.1.0.Final"

Spring配置:

 

    
    
        
        
        
        
    

    
    
        
        
        
        
        
        
    

bean的设置

public class User {

    private Integer uid;

    // 这些属性 可以查看jsr303的文档
    // message里的是验证不通过时你要显示的消息
    // 我用了消息国际化显示成这样{message.username.length} 在上述配置中又
    @NotBlank(message = "{message.username.length}")
    @Size(min = 1, message = "{message.username.length}")
    private String username;

    @NotBlank(message = "{message.password.length}")
    @Size(min = 8, message = "{message.password.length}")
    private String password;

    // no check
    private String email;
    
    // 省略getter setter
}

验证数据,只需要在要验证的对象上加上@Validated注解,当验证不通过时会把错误结果给到BindingResult中,按照需求给用户进行提示。

@RequestMapping(value = "/doLogin", method = RequestMethod.POST)
@ResponseBody
public BaseDTO doLogin(@Validated User user, BindingResult bindingResult){
    if (bindingResult.hasErrors()) {
        StringBuilder stringBuilder = new StringBuilder();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            stringBuilder.append(fieldError.getDefaultMessage()).append(",");
        }
        stringBuilder.deleteCharAt(stringBuilder.length() - 1);
        throw new UserException(stringBuilder.toString(), 0);
    }
    return null;
}
分组校验

首先定义一个校验分组:

public interface ValidGroupLogin {

    //接口中不需要定义任何方法,仅仅是对不同的校验规则进行分组
    //此分组只校验用户名和密码

}

先是在bean上设好分组

@NotBlank(message = "{message.username.length}", groups = ValidGroupLogin.class)

然后在controller中使用

@Validated(groups = ValidGroupLogin.class)
国际化

Spring配置:


    
        
        
        
        
        
    

    
    
        
    

    
    
    
        
    

文件所在位置

文件的内容(一份中文,一份英文,一份默认也是中文),其中数据校验也使用的这些个文件
中文:

Title=欢迎
Content=内容
Footer=欢迎捧场
GoHome=前往主页

message.username.length=用户名不能为空
message.password.length=密码要大于等于8位
message.uid.error=参数错误
message.uid.length=参数长度过长

英文:

Title=Welcome
Content=content
Footer=Welcome to join
GoHome=Go

message.username.length=username must be not null
message.password.length=password more than 8 length must
message.uid.error=param error
message.uid.length=param so long

thymeleaf中可以这样使用:

文件上传

老样子Spring配置:



    
    
        
        
        
        
    

前端:

控制器层:multipartFile就是用户上传的文件,MultipartFile[] multipartFiles可以变成多文件上传。

@RequestMapping(value = "/uploadHeadImage", method = RequestMethod.POST)
@ResponseBody
public BaseDTO uploadHeadImage(@RequestParam("file") MultipartFile multipartFile,
                               @RequestParam(value = "uid") Integer uid) {
        // 保存到指定路径
        multipartFile.transferTo(orginFile); 
        return null;
}
拦截器

    
        
        
    

拦截器类,继承HandlerInterceptor:

public class SuperSpringFilter implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        // 权限校验,不是所有人都可以操作数据库
        if ("/api/v2/text/checkText".equals(httpServletRequest.getRequestURI())) {
            if (httpServletRequest.getSession().getAttribute("uid").equals(1)) {

            }
        }

        httpServletRequest.setCharacterEncoding("UTF-8");
        return true;
    }

    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        if ("/welcome.html".equals(httpServletRequest.getRequestURI())) {
            httpServletResponse.setDateHeader("Expires", System.currentTimeMillis() + 2000 * 3600);
        }
    }

    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

多个拦截器生命周期:

返回JSON数据

其实早在之前就用到了,还是配置:






    
        
            
                application/json;charset=UTF-8
            
        
    

    
    
        
            
                
            
        
    

然后再需要返回json的地方加上@ResponseBody注解就可以了

下载

其实吧,直接用HttpServletResponse写出数据流就行了,但既然用了框架,那就来折腾一下:
先在Spring设置一下返回字符串的编码格式:


        
            
                
                
                
            
        
    

    
    
        
            
                text/html;charset=utf-8
                application/json;charset=utf-8
            
        
    

然后在Controller写一个下载的方法:

@RequestMapping(value = "/download/{fileName}/", method = RequestMethod.GET)
public ResponseEntity springDownload(@PathVariable String fileName, HttpServletRequest request) {
    String url = request.getSession().getServletContext().getRealPath("/") + "static/" + fileName;

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    headers.setContentDispositionFormData("attachment", fileName);
    try {
        File file = new File(url);
        return new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
定时执行任务

首先确保类是被Spring扫描得到的(@Componet),然后加上一个@EnableScheduling注解:

@Componet
@EnableScheduling
public class MeiZiTu {

    // 表示每天8点运行一次
    @Scheduled(cron = "0 0 8 * * ?")
    public void upDay() {
        System.out.println("8点啦");
    }
}

一些表达式的例子:

CRON表达式    含义 
"0 0 12 * * ?"    每天中午十二点触发 
"0 15 10 ? * *"    每天早上10:15触发 
"0 15 10 * * ?"    每天早上10:15触发 
"0 15 10 * * ? *"    每天早上10:15触发 
"0 15 10 * * ? 2005"    2005年的每天早上10:15触发 
"0 * 14 * * ?"    每天从下午2点开始到2点59分每分钟一次触发 
"0 0/5 14 * * ?"    每天从下午2点开始到2:55分结束每5分钟一次触发 
"0 0/5 14,18 * * ?"    每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发 
"0 0-5 14 * * ?"    每天14:00至14:05每分钟一次触发 
"0 10,44 14 ? 3 WED"    三月的每周三的14:10和14:44触发 
"0 15 10 ? * MON-FRI"    每个周一、周二、周三、周四、周五的10:15触发 
使用java类配置Servlet,Spring
@Configuration
public class DruidConfiguration implements WebApplicationInitializer {
    
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        DispatcherServlet servlet = new DispatcherServlet();


    }
    
    @Bean
    public User user() {
        return new User();
    }
}
全局异常捕获,返回json数据

能被包扫描到:

@ControllerAdvice
public class DefaultExceptionHandle {

    private static final Logger logger = LogManager.getLogger(DefaultExceptionHandle.class);
    
    // 通用异常
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public BaseDTO jsonErrorHandler(Exception e) {
        logger.error(e);
        return new BaseDTO(ResultEnums.UNKNOW_ERROR, false);
    }

    // 用户异常
    @ExceptionHandler(value = UserException.class)
    @ResponseBody
    public BaseDTO makeUserEception(UserException ue) {
        logger.error(ue);
        return new BaseDTO(ue.getStatus(), ue.getMessage(), false);
    }

}
AspectJ支持

Spring AOP 处理Http请求的记录:
Spring配置文件的使用:


    
    

使用:

@Aspect
@Component
public class HttpAspect {

    private static final Logger logger = LogManager.getLogger(HttpAspect.class);

    // Pointcut表示要切哪个点, *表示所有方法, ..表示任意参数
    // UserController下的所有方法进行aop拦截,这样我们可以在方法的声明周期中执行日志记录。
    @Pointcut("execution(public * com.test.controller.base.UserController.*(..))")
    public void log() {
    }

    // Before表示在方法执行之前
    @Before("log()")
    public void before(JoinPoint joinPoint) {
        // 记录http请求,url,method,client-ip,请求的方法,请求的参数
        logger.debug("Before=====================");

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        logger.debug("url={}", request.getRequestURL());
        logger.debug("method={}", request.getMethod());
        logger.debug("ip={}", request.getRemoteAddr() + ":" + request.getRemoteHost());

        // 类名
        logger.debug("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        // 参数
        logger.debug("class_args={}", joinPoint.getArgs());
    }

    // After 表示在方法执行后
    @After("log()")
    public void after() {
        logger.debug("After===================== 

");
    }

    // 返回的值
    @AfterReturning(returning = "o", pointcut = "log()")
    public void afterReturning(Object o) {
        logger.debug("response={}", o.toString());
    }

}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67373.html

相关文章

  • 面试题:SpringMVCStruts2的区别

    摘要:的入口是,而是这里要指出,和是不同的。以前认为是的一种特殊,这就导致了二者的机制不同,这里就牵涉到和的区别了。开发效率和性能高于。的实现机制有以自己的机制,用的是独立的方式。 1、Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上SpringMVC...

    isaced 评论0 收藏0
  • 【Java】基于Maven搭建Spring+SpringMVC+Mybatis框架

    摘要:关于的配置,可以参考这篇文章的第一个小节配置模板引擎搭什么搭直接用脚手架不行吗下载就能用下载就能用下载就能用码云咳咳,开个玩笑,如果本着学习态度的话,那就慢慢啃吧搭建空的项目使用搭建基本的空项目填写和,,选择项目的地址,在新的窗口打开最 关于springMVC的配置,可以参考这篇文章的第一个小节:【java】intellij idea SpringMVC 配置FreeMarker模板引...

    edagarli 评论0 收藏0
  • “过时”的SpringMVC我们到底在用什么?深入分析DispatchServlet源码

    摘要:问题来了,我们到底还在用吗答案是,不全用。后者是初始化的配置,主要是的配置。启动类测试启动项目后,在浏览器里面输入。通过查询已装载的,并且支持该而获取的。按照前面对的描述,对于而言,这个必定是。的核心在的方法中。 之前已经分析过了Spring的IOC(《零基础带你看Spring源码——IOC控制反转》)与AOP(《从源码入手,一文带你读懂Spring AOP面向切面编程》)的源码,本次...

    array_huang 评论0 收藏0
  • springMVC流程的学习理解

    摘要:先用一个图来表示基本流程图这个网上很容易找到基本流程图用户发送请求到前端控制器前端控制器是的重要部分,位于中心,提供整个框架访问点,起到交换的作用,而且与容器集成。在配置这个监听器,启动容器时,就会默认执行它实现的方法。 先用一个图来表示基本流程图这个网上很容易找到 基本流程图 showImg(https://segmentfault.com/img/bVbfDiV?w=1340&h...

    didikee 评论0 收藏0
  • [转载]使用IntelliJ IDEA开发SpringMVC网站(二)框架配置

    摘要:为了能够处理中文的请求,再配置一个,以避免请求中文出现乱码情况至此,配置完毕。一般为一些基本的,用于进行相应的页面显示,用于处理网站的请求。现在,需要配置来运行该项目。 摘要讲解如何配置SpringMVC框架xml,以及如何在Tomcat中运行转载请注明出处:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生)。 注:此文承接上一文:使用IntelliJ IDEA开发Sprin...

    baukh789 评论0 收藏0
  • Java后端

    摘要:,面向切面编程,中最主要的是用于事务方面的使用。目标达成后还会有去构建微服务,希望大家多多支持。原文地址手把手教程优雅的应用四手把手实现后端搭建第四期 SpringMVC 干货系列:从零搭建 SpringMVC+mybatis(四):Spring 两大核心之 AOP 学习 | 掘金技术征文 原本地址:SpringMVC 干货系列:从零搭建 SpringMVC+mybatis(四):Sp...

    joyvw 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<