当前位置:   article > 正文

第十二章 Spring MVC 框架扩展和SSM框架整合(2023版本IDEA)

第十二章 Spring MVC 框架扩展和SSM框架整合(2023版本IDEA)


  前面章节中,系统的升级改造过程中遗留了一些和异步请求相关的功能,本章将完善这些内容,并学习Spring MVC 框架中数据转换、数据格式化处理的相关知识。(如果没有了解可以去我主页看看 第一至十一章的内容来学习)通过学习本章内容,我们将理解Spring MVC 框架处理JSON时间传递、多视图解析器的工作原理和数据格式转换的基本概念及流程,完成Spring MVC+Spring+MyBatis(SSM)框架的搭建工作。

12.1 Spring MVC 框架处理JSON数据

  JSON格式数据在现阶段的Web项目开发中扮演着非常重要的角色。在前端页面和后台交互的过程中,需要一种格式清晰、高效且两端都可以轻松使用的数据格式做交互的媒介,JSON正可以满足这一需求。

12.1.1 JSON数据的传递处理

在Java中处理JSON数据的传递通常涉及到序列化和反序列化操作。序列化是将Java对象转换为JSON格式的字符串,以便可以将其存储或通过网络传输;反序列化则是将JSON格式的字符串转换回Java对象。在Java中,有很多库可以帮助我们完成这些操作,如Jackson、Gson等。

以下是一个使用Jackson库进行JSON数据传递处理的简单示例。

1. 添加Jackson依赖
首先,你需要在你的项目中添加Jackson的依赖。如果你使用的是Maven,可以在pom.xml文件中添加如下依赖:

<dependency>  
    <groupId>com.fasterxml.jackson.core</groupId>  
    <artifactId>jackson-databind</artifactId>  
    <version>2.13.0</version>  
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

2. 创建一个Java类
接下来,创建一个Java类,用于表示你要序列化和反序列化的数据。

public class User {  
    private String name;  
    private int age;  
  
    // 构造方法、getter和setter省略  
  
    public User(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
  
    // 省略getter和setter方法  
  
    @Override  
    public String toString() {  
        return "User{" +  
                "name='" + name + '\'' +  
                ", age=" + age +  
                '}';  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

3. 序列化Java对象为JSON字符串
现在,你可以使用Jackson的ObjectMapper类来将User对象序列化为JSON字符串。

import com.fasterxml.jackson.databind.ObjectMapper;  
  
public class JsonSerializerExample {  
    public static void main(String[] args) {  
        try {  
            User user = new User("John Doe", 30);  
  
            ObjectMapper objectMapper = new ObjectMapper();  
            String jsonString = objectMapper.writeValueAsString(user);  
  
            System.out.println(jsonString);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

4. 反序列化JSON字符串为Java对象
同样地,你可以使用ObjectMapper类将JSON字符串反序列化为Java对象。

import com.fasterxml.jackson.databind.ObjectMapper;  
  
public class JsonDeserializerExample {  
    public static void main(String[] args) {  
        try {  
            String jsonString = "{\"name\":\"Jane Doe\",\"age\":28}";  
  
            ObjectMapper objectMapper = new ObjectMapper();  
            User user = objectMapper.readValue(jsonString, User.class);  
  
            System.out.println(user);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

以上代码展示了如何在Java中使用Jackson库来处理JSON数据的序列化和反序列化。当然,你也可以选择使用Gson等其他库来完成这些操作,不同的库在使用上可能略有不同,但基本思想是一致的。

12.1.2 JSON数据传递过程中的中文乱码和日期问题

在处理JSON数据传递时,中文乱码和日期格式问题是很常见的。这些问题通常发生在数据被序列化为JSON字符串,或者从JSON字符串反序列化为Java对象的过程中。以下是如何在Java中处理这些问题的示例,这里仍然使用Jackson库。

1. 中文乱码问题
中文乱码问题通常是因为字符集不匹配导致的。在Java中,确保你的源数据(如字符串、文件等)和目标环境(如JSON库、网络传输等)都使用UTF-8或其他支持中文的字符集。Jackson库默认使用UTF-8编码,所以通常不需要额外配置。

但是,如果你在处理文件或网络传输时遇到了中文乱码,请确保在读写这些资源时也使用了正确的字符集。

2. 日期格式问题
日期格式问题通常是因为JSON字符串中的日期格式与Java对象中的日期类型(如java.util.Date、java.time.LocalDate等)不匹配。Jackson提供了多种方式来处理这个问题,包括自定义序列化器和反序列化器,以及使用@JsonFormat注解。

使用@JsonFormat注解
你可以在你的Java对象的日期字段上使用@JsonFormat注解来指定日期格式。这样,Jackson在序列化和反序列化时就会按照指定的格式来处理这些字段。

import com.fasterxml.jackson.annotation.JsonFormat;  
import java.util.Date;  
  
public class Event {  
    private String name;  
  
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")  
    private Date startTime;  
  
    // 构造方法、getter和setter省略  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这个例子中,startTime字段会被序列化为"yyyy-MM-dd HH:mm:ss"格式的字符串,并且在反序列化时也会按照这个格式来解析。

自定义序列化器和反序列化器
对于更复杂的日期处理,你可能需要自定义序列化器和反序列化器。这可以通过继承JsonSerializer和JsonDeserializer类,并实现相应的方法来完成。

但是,对于大多数常见情况,使用@JsonFormat注解已经足够。

完整示例
下面是一个完整的示例,展示了如何序列化一个包含中文和日期的Java对象为JSON字符串,并反序列化回来。

import com.fasterxml.jackson.annotation.JsonFormat;  
import com.fasterxml.jackson.databind.ObjectMapper;  
  
import java.io.IOException;  
import java.text.ParseException;  
import java.text.SimpleDateFormat;  
import java.util.Date;  
  
public class JsonExample {  
    public static void main(String[] args) {  
        try {  
            Event event = new Event("活动名称", new Date());  
  
            ObjectMapper objectMapper = new ObjectMapper();  
            String jsonString = objectMapper.writeValueAsString(event);  
            System.out.println(jsonString);  
  
            Event deserializedEvent = objectMapper.readValue(jsonString, Event.class);  
            System.out.println(deserializedEvent);  
  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
  
    static class Event {  
        private String name;  
  
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")  
        private Date startTime;  
  
        public Event(String name, Date startTime) {  
            this.name = name;  
            this.startTime = startTime;  
        }  
  
        // 省略getter和setter方法  
  
        @Override  
        public String toString() {  
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
            sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+8"));  
            return "Event{" +  
                    "name='" + name + '\'' +  
                    ", startTime=" + sdf.format(startTime) +  
                    '}';  
        }  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

请注意,我在@JsonFormat注解中添加了timezone = "GMT+8"属性来确保日期时间按照东八区的时间来格式化。同时,在toString方法中,我也使用了SimpleDateFormat来格式化日期,并设置了相同的时区,以确保打印出的日期时间与JSON中的一致。

12.1.3 多视图解析器

在Java Web开发中,特别是使用Spring MVC框架时,多视图解析器(Multiple View Resolvers)允许你根据请求的不同类型或条件来解析不同的视图。例如,你可能想要对于JSON请求使用JSON视图解析器,而对于HTML请求使用JSP或Thymeleaf等模板引擎。

下面是一个使用Spring MVC配置多视图解析器的简单示例。这个示例将包括两个视图解析器:一个用于JSP文件,另一个假设是一个用于某种非HTML视图(如JSON)的自定义视图解析器(实际上,对于JSON,你可能不需要专门的视图解析器,因为你可以直接在Controller中返回数据,并使用@ResponseBody注解)。但这里为了演示目的,我将展示如何配置两个视图解析器。

首先,你需要在Spring配置文件中(或者如果你使用的是Java配置,则在配置类中)配置视图解析器。

Java配置示例
如果你使用的是Java配置(基于@Configuration的类),可以像下面这样配置多视图解析器:

import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.web.servlet.ViewResolver;  
import org.springframework.web.servlet.view.InternalResourceViewResolver;  
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;  
  
import java.util.Properties;  
  
@Configuration  
public class ViewResolverConfig {  
  
    @Bean  
    public InternalResourceViewResolver internalResourceViewResolver() {  
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();  
        resolver.setPrefix("/WEB-INF/views/");  
        resolver.setSuffix(".jsp");  
        return resolver;  
    }  
  
    // 注意:实际上对于JSON,你可能不需要专门的ViewResolver  
    // 这里仅作为示例,展示如何配置另一个ViewResolver  
    @Bean  
    public ViewResolver jsonViewResolver() {  
        // 自定义的ViewResolver,这里用MappingJackson2JsonView作为示例  
        // 但在实际中,你可能直接在Controller中返回数据并使用@ResponseBody  
        return new ViewResolver() {  
            @Override  
            public View resolveViewName(String viewName, Locale locale) throws Exception {  
                // 这里可以根据viewName或其他条件来返回不同的View  
                // 但对于JSON,这通常不是必需的  
                MappingJackson2JsonView jsonView = new MappingJackson2JsonView();  
                // 可以设置一些属性,比如是否美化JSON输出等  
                jsonView.setPrettyPrint(true);  
                return jsonView;  
            }  
        };  
    }  
  
    // 注意:上面的jsonViewResolver实际上并不常用,因为Spring MVC提供了  
    // 更好的方式来处理JSON响应,即直接在Controller中返回对象并使用@ResponseBody注解。  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

注意事项

  1. 对于JSON:如上所述,你通常不需要为JSON响应配置专门的视图解析器。相反,你可以在Controller方法上使用@ResponseBody注解,并直接返回对象或ResponseEntity,Spring MVC会自动使用配置的HttpMessageConverter(如MappingJackson2HttpMessageConverter)来将对象序列化为JSON。
  2. 视图解析器顺序:如果有多个视图解析器,Spring MVC会按照配置的顺序尝试它们,直到找到能解析给定视图名的解析器为止。
  3. 自定义视图解析器:如果你需要特殊的视图处理逻辑(例如,基于请求参数动态选择视图),你可以实现自己的ViewResolver。但请注意,对于大多数用例,Spring MVC提供的标准视图解析器应该就足够了。

12.2 Spring MVC 框架中的数据格式转换

在Spring MVC框架中,数据格式转换是一个常见且重要的功能,它允许你自动地在请求参数、模型属性和响应体之间转换数据格式。Spring MVC通过一系列机制来实现这一功能,包括但不限于类型转换(ConversionService)、格式化(Formatter)、编辑器(PropertyEditor)以及@RequestBody和@ResponseBody注解的使用。

下面我将通过几个示例来说明如何在Spring MVC中实现数据格式转换。

1. 使用@RequestBody和@ResponseBody进行JSON转换
这是最常见的数据格式转换场景之一,通常用于RESTful API的开发。Spring MVC通过配置HttpMessageConverters来支持JSON的自动序列化和反序列化。

Controller示例:

import org.springframework.web.bind.annotation.PostMapping;  
import org.springframework.web.bind.annotation.RequestBody;  
import org.springframework.web.bind.annotation.ResponseBody;  
import org.springframework.web.bind.annotation.RestController;  
  
@RestController  
public class UserController {  
  
    @PostMapping("/user")  
    public @ResponseBody User createUser(@RequestBody User user) {  
        // 处理用户数据...  
        return user; // 直接返回User对象,Spring MVC会将其转换为JSON  
    }  
}  
  
// 假设有一个User类  
public class User {  
    private String name;  
    private int age;  
    // getters and setters  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在这个例子中,Spring MVC自动将传入的JSON数据转换为User对象,并将返回的User对象序列化为JSON。这通常是通过配置Jackson或Gson作为HttpMessageConverter来实现的。

2. 自定义类型转换器(ConversionService)
当你需要在Spring MVC的绑定过程中自定义类型转换逻辑时,可以实现并注册Converter或ConverterFactory,并通过ConversionService进行管理。

自定义转换器示例:

import org.springframework.core.convert.converter.Converter;  
import org.springframework.stereotype.Component;  
  
@Component  
public class StringToUserConverter implements Converter<String, User> {  
  
    @Override  
    public User convert(String source) {  
        // 这里是自定义的转换逻辑,例如从某种格式的字符串解析User对象  
        // ...  
        return new User(); // 示例返回  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

然后,你需要在Spring MVC的配置中注册这个转换器。如果你使用的是Java配置,可以通过WebMvcConfigurer接口来实现。

3. 使用Formatter进行字段格式化
Formatter接口用于在Spring MVC的绑定过程中格式化字段。与Converter不同,Formatter是针对特定字段和类型的,并且它考虑了语言环境。

自定义Formatter示例:

import org.springframework.format.Formatter;  
import java.text.ParseException;  
import java.text.SimpleDateFormat;  
import java.util.Date;  
import java.util.Locale;  
  
public class CustomDateFormatter implements Formatter<Date> {  
  
    private final String dateFormat;  
  
    public CustomDateFormatter(String dateFormat) {  
        this.dateFormat = dateFormat;  
    }  
  
    @Override  
    public String print(Date object, Locale locale) {  
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat, locale);  
        return sdf.format(object);  
    }  
  
    @Override  
    public Date parse(String text, Locale locale) throws ParseException {  
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat, locale);  
        return sdf.parse(text);  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

然后,你需要在Spring MVC的配置中注册这个Formatter。

结论
Spring MVC提供了多种机制来实现数据格式转换,从简单的JSON序列化和反序列化,到复杂的自定义类型转换和字段格式化。你可以根据具体需求选择合适的机制来实现数据格式转换。

12.2.1 Spring MVC 框架数据转换流程

在Spring MVC框架中,数据转换流程是一个复杂但高度集成的过程,它涉及到多个组件和接口。这里,我将概述Spring MVC中数据转换的基本流程,并提供一些关键的Java代码片段来说明这一过程。

数据转换流程概述

  1. 请求接收: 客户端(如浏览器或另一个服务)发送HTTP请求到服务器。
  2. 请求分发: Spring MVC的DispatcherServlet接收请求,并根据请求URL和配置的映射找到对应的Controller和HandlerMethod。
  3. 参数解析: DispatcherServlet使用HandlerMethodArgumentResolver接口的实现来解析请求中的参数。这包括从请求体(@RequestBody)、路径变量、查询参数等中解析数据。
  4. 数据转换:
    类型转换器(ConversionService): 用于在简单类型之间转换,如String到Integer。
    格式化器(Formatter): 用于特定类型的格式化,如日期或货币,考虑语言环境。
    HTTP消息转换器(HttpMessageConverter): 用于在请求体和响应体中读写数据,如JSON、XML等。
  5. 方法调用: 解析并转换后的参数被传递给Controller中的方法。
  6. 结果处理: Controller方法执行后,返回的结果(可能是视图名、模型数据或响应体)被处理。
  7. 响应发送: 处理后的结果通过DispatcherServlet和配置的视图解析器(如果需要的话)发送给客户端。

关键代码片段
1. 控制器方法示例

@RestController  
public class UserController {  
  
    @PostMapping("/user")  
    public User createUser(@RequestBody User user) {  
        // 处理用户数据...  
        return user; // 直接返回User对象,Spring MVC会将其转换为JSON  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2. 配置HttpMessageConverter(通常通过配置类自动完成)

@Configuration  
public class WebConfig implements WebMvcConfigurer {  
  
    @Override  
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {  
        converters.add(new MappingJackson2HttpMessageConverter()); // Jackson JSON转换器  
        // 可以添加其他转换器,如XML等  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

注意:在Spring Boot应用中,MappingJackson2HttpMessageConverter通常会自动配置,无需手动添加。

3. 自定义Formatter注册

@Configuration  
public class FormatterConfig implements FormattingConversionServiceConfigurer {  
  
    @Override  
    public void configureFormattingConversionService(FormattingConversionService conversionService) {  
        conversionService.addFormatter(new CustomDateFormatter("yyyy-MM-dd"));  
    }  
  
    // CustomDateFormatter的实现(如上所示)  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4. 自定义Converter注册(如果需要)
自定义Converter的注册通常通过将其声明为Spring组件(使用@Component注解)来自动完成。但是,如果你需要更细粒度的控制,可以在配置类中通过ConversionServiceFactoryBean来注册它们。

5. 自定义HandlerMethodArgumentResolver(高级用法)
如果你需要处理特殊的参数解析逻辑,可以实现HandlerMethodArgumentResolver接口。这通常用于处理Spring MVC默认不支持的复杂场景。

@Component  
public class CustomArgumentResolver implements HandlerMethodArgumentResolver {  
    // 实现解析逻辑  
}  
  
// 然后在配置类中注册它  
@Override  
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {  
    resolvers.add(new CustomArgumentResolver());  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

注意:上面的addArgumentResolvers方法需要在实现了WebMvcConfigurer接口的类中重写。

结论
Spring MVC的数据转换流程是一个高度可配置和可扩展的过程,它允许开发者通过实现各种接口和注册组件来定制请求处理和响应生成的行为。上述代码片段提供了数据转换流程中一些关键步骤的示例。

12.2.2 编写自定义转换器

在Java中,特别是在使用Spring框架时,编写自定义转换器(Converter)通常涉及实现org.springframework.core.convert.converter.Converter接口或继承org.springframework.core.convert.converter.ConverterFactory(如果你需要更复杂的转换逻辑,能够处理多个源类型或目标类型)。下面是一个简单的自定义转换器示例,它将一个字符串转换为自定义的User对象。

首先,定义你的User类(假设它有两个属性:id和name):

public class User {  
    private Long id;  
    private String name;  
  
    // 构造函数、getter和setter省略  
  
    public User(Long id, String name) {  
        this.id = id;  
        this.name = name;  
    }  
  
    // getters and setters  
    public Long getId() {  
        return id;  
    }  
  
    public void setId(Long id) {  
        this.id = id;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    // toString()方法可以帮助我们在转换后看到结果  
    @Override  
    public String toString() {  
        return "User{" +  
               "id=" + id +  
               ", name='" + name + '\'' +  
               '}';  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

然后,编写你的自定义转换器,它实现了Converter接口:

import org.springframework.core.convert.converter.Converter;  
import org.springframework.stereotype.Component;  
  
@Component  
public class StringToUserConverter implements Converter<String, User> {  
  
    @Override  
    public User convert(String source) {  
        // 这里是一个简单的字符串解析逻辑,假设字符串格式为"id,name"  
        String[] parts = source.split(",");  
        if (parts.length != 2) {  
            throw new IllegalArgumentException("String must be in the format 'id,name'");  
        }  
  
        try {  
            Long id = Long.parseLong(parts[0].trim());  
            String name = parts[1].trim();  
            return new User(id, name);  
        } catch (NumberFormatException e) {  
            throw new IllegalArgumentException("ID must be a valid number", e);  
        }  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

注意,这里我使用了@Component注解来标记这个转换器,这样Spring就能够自动检测到它并注册到Spring的上下文中。但是,对于自定义转换器,你还需要确保Spring知道如何使用它。这通常是通过在配置类中注册ConversionService来完成的,但如果你使用的是Spring Boot,并且你的转换器被标记为@Component,那么Spring Boot会自动为你处理这一切。

现在,当Spring MVC的控制器需要从一个请求参数或请求体中解析一个User对象时,并且如果请求中提供了符合"id,name"格式的字符串,Spring就会使用你的StringToUserConverter来执行转换。

请注意,上面的示例是一个非常简单的字符串到对象的转换。在实际应用中,你可能需要处理更复杂的情况,比如从JSON字符串到对象的转换,这通常是通过配置HttpMessageConverter(如Jackson或Gson的转换器)来完成的,而不是通过自定义的Converter。然而,对于那些不能通过标准HTTP消息转换器直接处理的情况,自定义转换器就非常有用了。

12.2.3 使用@InitBinder装配自定义编辑器

在Spring MVC中,@InitBinder注解用于在控制器中声明一个初始化数据绑定的方法,这个方法可以用来注册自定义的属性编辑器(PropertyEditor)或格式化器(Formatter)。但是,从Spring 3.0开始,推荐使用Formatter接口和FormattingConversionService来代替PropertyEditor,因为Formatter提供了更灵活的类型安全转换。不过,为了完整性,我将首先展示如何使用PropertyEditor,然后展示如何使用Formatter。

使用PropertyEditor
首先,你需要实现一个PropertyEditor来执行自定义的字符串到对象的转换。但是,请注意,直接在控制器中使用PropertyEditor并不是最佳实践,因为这会使得你的控制器与Spring的ConversionService机制解耦。不过,为了说明目的,我会展示一个简单的例子。

import org.springframework.beans.propertyeditors.CustomDateEditor;  
import org.springframework.stereotype.Controller;  
import org.springframework.web.bind.WebDataBinder;  
import org.springframework.web.bind.annotation.InitBinder;  
  
// 注意:这里我实际上不会展示自定义的PropertyEditor,而是使用CustomDateEditor作为示例  
@Controller  
public class MyController {  
  
    @InitBinder  
    public void initBinder(WebDataBinder binder) {  
        // 示例:注册一个自定义的日期编辑器  
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  
        dateFormat.setLenient(false);  
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));  
  
        // 如果你要注册自定义的PropertyEditor,你需要实现PropertyEditorSupport并覆盖相应的方法  
        // binder.registerCustomEditor(YourClass.class, new YourCustomPropertyEditor());  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

请注意,上面的例子实际上展示了如何注册一个CustomDateEditor,而不是一个完全自定义的PropertyEditor。对于自定义类型,你需要实现PropertyEditorSupport类并重写setAsText和getAsText方法。

使用Formatter
现在,让我们看一个使用Formatter的示例,这是更现代且推荐的方法。

首先,实现Formatter接口:

import org.springframework.format.Formatter;  
import java.text.ParseException;  
import java.text.SimpleDateFormat;  
import java.util.Date;  
import java.util.Locale;  
  
public class CustomDateFormatter implements Formatter<Date> {  
  
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  
  
    @Override  
    public String print(Date object, Locale locale) {  
        return dateFormat.format(object);  
    }  
  
    @Override  
    public Date parse(String text, Locale locale) throws ParseException {  
        return dateFormat.parse(text);  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

然后,在你的配置中注册这个Formatter(如果你使用的是Java配置):

import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.format.FormatterRegistry;  
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;  
  
@Configuration  
public class WebConfig implements WebMvcConfigurer {  
  
    @Override  
    public void addFormatters(FormatterRegistry registry) {  
        registry.addFormatter(customDateFormatter());  
    }  
  
    @Bean  
    public CustomDateFormatter customDateFormatter() {  
        return new CustomDateFormatter();  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

或者,如果你使用的是XML配置,你可以通过mvc:annotation-driven标签的conversion-service属性来引用一个自定义的ConversionService,该服务注册了你的Formatter。

使用Formatter比PropertyEditor更灵活且类型安全,因为它允许你在方法签名中明确指定源类型和目标类型。此外,Formatter是Spring 3.0及更高版本中推荐的数据绑定和格式化机制。

12.3 SSM框架整合

SSM(Spring + Spring MVC + MyBatis)框架整合是Java Web开发中非常流行的一种架构方式。这里我将提供一个简单的示例来说明如何整合这三个框架。

1. 项目结构
首先,我们需要创建一个Maven项目,并设置其pom.xml文件以包含必要的依赖项。

<dependencies>  
    <!-- Spring -->  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-context</artifactId>  
        <version>5.3.10</version>  
    </dependency>  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-webmvc</artifactId>  
        <version>5.3.10</version>  
    </dependency>  
  
    <!-- MyBatis -->  
    <dependency>  
        <groupId>org.mybatis</groupId>  
        <artifactId>mybatis</artifactId>  
        <version>3.5.7</version>  
    </dependency>  
    <dependency>  
        <groupId>org.mybatis.spring.boot</groupId>  
        <artifactId>mybatis-spring-boot-starter</artifactId>  
        <version>2.1.4</version>  
    </dependency>  
  
    <!-- 数据库连接池 -->  
    <dependency>  
        <groupId>com.zaxxer</groupId>  
        <artifactId>HikariCP</artifactId>  
        <version>4.0.3</version>  
    </dependency>  
  
    <!-- 数据库驱动 -->  
    <dependency>  
        <groupId>mysql</groupId>  
        <artifactId>mysql-connector-java</artifactId>  
        <version>8.0.25</version>  
    </dependency>  
  
    <!-- Servlet API -->  
    <dependency>  
        <groupId>javax.servlet</groupId>  
        <artifactId>javax.servlet-api</artifactId>  
        <version>4.0.1</version>  
        <scope>provided</scope>  
    </dependency>  
  
    <!-- JSP API -->  
    <dependency>  
        <groupId>javax.servlet.jsp</groupId>  
        <artifactId>javax.servlet.jsp-api</artifactId>  
        <version>2.3.3</version>  
        <scope>provided</scope>  
    </dependency>  
  
    <!-- JSTL -->  
    <dependency>  
        <groupId>javax.servlet.jsp.jstl</groupId>  
        <artifactId>jstl-api</artifactId>  
        <version>1.2</version>  
    </dependency>  
    <dependency>  
        <groupId>taglibs</groupId>  
        <artifactId>standard</artifactId>  
        <version>1.1.2</version>  
    </dependency>  
</dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

2. 配置Spring
在src/main/resources目录下创建applicationContext.xml文件来配置Spring的Bean。

<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
       http://www.springframework.org/schema/beans/spring-beans.xsd">  
  
    <!-- 配置数据源 -->  
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"  
          destroy-method="close">  
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>  
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/yourdb?serverTimezone=UTC"/>  
        <property name="username" value="root"/>  
        <property name="password" value="password"/>  
    </bean>  
  
    <!-- 配置SqlSessionFactory -->  
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSource"/>  
        <!-- 引入MyBatis配置文件 -->  
        <property name="configLocation" value="classpath:mybatis-config.xml"/>  
    </bean>  
  
    <!-- Mapper扫描 -->  
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
        <property name="basePackage" value="com.example.mapper"/>  
    </bean>  
  
    <!-- 其他Bean配置 -->  
</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

3. 配置Spring MVC
在web.xml中配置Spring MVC的前端控制器(DispatcherServlet)和Spring的监听器

12.3.1 SSM 框架简介

SSM(Spring + Spring MVC + MyBatis)框架是一个流行的Java Web开发框架组合,它结合了Spring的依赖注入和面向切面编程(AOP)能力、Spring MVC的Web层处理能力和MyBatis的持久层处理能力。下面我将简要介绍这三个框架的作用,并提供一些基本的Java代码示例来展示它们是如何协同工作的。

1. Spring
Spring是一个全面的、控制反转(IoC)和面向切面编程(AOP)的容器框架。它主要用于管理Java应用中的对象(称为beans),并促进松耦合设计。

Spring Bean 示例

@Component  
public class UserService {  
  
    @Autowired  
    private UserMapper userMapper;  
  
    public User getUserById(int id) {  
        return userMapper.selectByPrimaryKey(id);  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2. Spring MVC
Spring MVC是一个基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架。它主要用于Web层的开发,将Web层进行职责解耦,使得开发者更容易进行开发。

Spring MVC Controller 示例

@Controller  
@RequestMapping("/user")  
public class UserController {  
  
    @Autowired  
    private UserService userService;  
  
    @GetMapping("/{id}")  
    public String getUser(@PathVariable("id") int id, Model model) {  
        User user = userService.getUserById(id);  
        model.addAttribute("user", user);  
        return "userView"; // 假设有一个名为userView的JSP页面来展示用户信息  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3. MyBatis
MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,简单的Java对象)映射成数据库中的记录。

MyBatis Mapper XML 示例

<mapper namespace="com.example.mapper.UserMapper">  
    <select id="selectByPrimaryKey" resultType="com.example.domain.User">  
        SELECT * FROM user WHERE id = #{id}  
    </select>  
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5

MyBatis Mapper 接口

public interface UserMapper {  
    User selectByPrimaryKey(int id);  
}
  • 1
  • 2
  • 3

12.3.2 SSM框架搭建

SSM(Spring + Spring MVC + MyBatis)框架的搭建涉及多个步骤,包括项目结构的设置、依赖的引入、配置文件的编写以及各层代码的编写等。下面是一个简化的SSM框架搭建过程及关键Java代码示例。

  1. 项目结构设置
    首先,你需要创建一个Java Web项目,并设置好项目的结构。一般来说,SSM项目的结构会包括以下几个部分:
    – src/main/java:存放Java源代码。
    – src/main/resources:存放配置文件(如Spring配置文件、MyBatis映射文件等)和静态资源(如图片、CSS、JS等)。
    – src/main/webapp:存放Web资源,如JSP页面、HTML文件等。
    – pom.xml(如果使用Maven):项目的依赖管理文件。

2. 依赖引入
如果你使用Maven作为项目管理和构建工具,你需要在pom.xml文件中引入SSM框架所需的依赖。这通常包括Spring框架、Spring MVC、MyBatis、数据库连接池(如HikariCP或DBCP)、Servlet API等。

例如,引入Spring和MyBatis的依赖可能如下所示:

<!-- Spring核心依赖 -->  
<dependency>  
    <groupId>org.springframework</groupId>  
    <artifactId>spring-context</artifactId>  
    <version>你的Spring版本</version>  
</dependency>  
<!-- Spring MVC依赖 -->  
<dependency>  
    <groupId>org.springframework</groupId>  
    <artifactId>spring-webmvc</artifactId>  
    <version>你的Spring版本</version>  
</dependency>  
<!-- MyBatis依赖 -->  
<dependency>  
    <groupId>org.mybatis</groupId>  
    <artifactId>mybatis</artifactId>  
    <version>你的MyBatis版本</version>  
</dependency>  
<!-- MyBatis与Spring整合依赖 -->  
<dependency>  
    <groupId>org.mybatis.spring.boot</groupId>  
    <artifactId>mybatis-spring-boot-starter</artifactId>  
    <version>你的版本</version>  
</dependency>  
<!-- 数据库连接池依赖(示例为HikariCP) -->  
<dependency>  
    <groupId>com.zaxxer</groupId>  
    <artifactId>HikariCP</artifactId>  
    <version>你的HikariCP版本</version>  
</dependency>  
<!-- 数据库驱动依赖(以MySQL为例) -->  
<dependency>  
    <groupId>mysql</groupId>  
    <artifactId>mysql-connector-java</artifactId>  
    <version>你的MySQL驱动版本</version>  
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

注意:上面的版本号需要替换为你项目中实际使用的版本号。

3. 配置文件编写
SSM框架通常需要编写Spring配置文件(如applicationContext.xml)、Spring MVC配置文件(如dispatcherServlet-servlet.xml)以及MyBatis配置文件(如mybatis-config.xml)等。但是,随着Spring Boot的普及,很多配置可以通过注解和application.properties/application.yml文件来完成,从而简化配置过程。

4. Java代码编写
实体类(Entity)

public class User {  
    private Integer id;  
    private String name;  
    private String email;  
    // 省略getter和setter方法  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Mapper接口

@Mapper  
public interface UserMapper {  
    User selectByPrimaryKey(Integer id);  
    // 其他数据库操作方法  
}
  • 1
  • 2
  • 3
  • 4
  • 5

Mapper XML
MyBatis Mapper XML文件用于定义SQL语句和映射规则。

<mapper namespace="com.example.mapper.UserMapper">  
    <select id="selectByPrimaryKey" resultType="com.example.domain.User">  
        SELECT * FROM user WHERE id = #{id}  
    </select>  
    <!-- 其他SQL映射 -->  
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Service层

@Service  
public class UserService {  
  
    @Autowired  
    private UserMapper userMapper;  
  
    public User getUserById(Integer id) {  
        return userMapper.selectByPrimaryKey(id);  
    }  
    // 其他业务逻辑方法  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Controller层

package com.example.controller;  
  
import com.example.service.UserService;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Controller;  
import org.springframework.web.bind.annotation.PostMapping;  
import org.springframework.web.bind.annotation.RequestBody;  
import org.springframework.web.bind.annotation.ResponseBody;  
  
@Controller  
public class UserController {  
  
    @Autowired  
    private UserService userService;  
  
    @PostMapping("/login")  
    @ResponseBody  
    public Map<String, Object> login(@RequestBody UserLoginDTO userLoginDTO) {  
        Map<String, Object> result = new HashMap<>();  
        User user = userService.login(userLoginDTO.getUsername(), userLoginDTO.getPassword());  
        if (user != null) {  
            result.put("code", 200);  
            result.put("message", "登录成功");  
            result.put("user", user);  
        } else {  
            result.put("code", 401);  
            result.put("message", "用户名或密码错误");  
        }  
        return result;  
    }  
  
    // 其他请求处理方法...  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/946564
推荐阅读
相关标签
  

闽ICP备14008679号