告别注解:无注解环境下向前台传递JSON数据的多种途径**
在Java Web开发中,我们常常依赖如Jackson、Gson等库提供的注解(如@JsonProperty、@JsonFormat、@JsonIgnore等)来精细控制对象到JSON字符串的序列化过程,并通过Spring框架的@ResponseBody注解便捷地将数据以JSON格式返回给前台,在某些特定场景下,我们可能希望避免使用这些注解,项目需要减少对特定库的依赖、注解可能引起序列化行为不符合预期、或者处于学习目的想了解底层原理,不使用注解,我们该如何向前台传递JSON数据呢?本文将探讨几种有效的实现方式。
核心思路:手动控制序列化与响应构建
不使用注解,并不意味着不能传递JSON,核心在于绕过框架的自动注解解析,转而通过手动方式或更底层的API来完成对象到JSON的转换以及HTTP响应的构建,以下是几种常见的实现策略:
手动序列化为JSON字符串,再通过原生Servlet响应
这是最基础也是最直接的方式,不依赖任何Spring MVC的注解,而是直接使用Java Servlet API来构建响应。
-
步骤:
- 获取
HttpServletResponse对象。 - 使用JSON库(如Jackson、Gson、Fastjson等)将Java对象手动序列化为JSON字符串。
- 设置响应头的
Content-Type为application/json;charset=UTF-8。 - 通过
PrintWriter或OutputStream将JSON字符串写入响应体。
- 获取
-
示例代码(使用Jackson和原生Servlet):
import com.fasterxml.jackson.databind.ObjectMapper; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class NoAnnotationJsonServlet extends HttpServlet { private ObjectMapper objectMapper = new ObjectMapper(); // 线程安全,可复用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { // 1. 准备要返回的Java对象 User user = new User("张三", 30, "zhangsan@example.com"); // 2. 手动序列化为JSON字符串 String jsonString = objectMapper.writeValueAsString(user); // 3. 设置响应头 resp.setContentType("application/json;charset=UTF-8"); resp.setCharacterEncoding("UTF-8"); // 4. 写入响应体 resp.getWriter().write(jsonString); } } // 假设的User类,没有任何注解 class User { private String name; private int age; private String email; // 构造方法、getters和setters public User(String name, int age, String email) { this.name = name; this.age = age; this.email = email; } // 省略getter和setter... } -
优缺点:
- 优点: 完全不依赖框架注解,底层可控,适合学习或特殊场景。
- 缺点: 代码量较大,需要手动处理序列化和响应构建,在大型项目中显得繁琐。
使用Spring MVC的HttpEntity或ResponseEntity
虽然@ResponseBody内部也依赖序列化,但如果我们想避免在POJO上使用注解,同时仍利用Spring MVC的便捷性,可以使用HttpEntity或ResponseEntity。
-
ResponseEntity: 允许我们完全控制HTTP响应体、头部和状态码。 -
HttpEntity: 类似于ResponseEntity,但不包含状态码。 -
步骤:
- 在Controller方法中,返回
ResponseEntity<T>或HttpEntity<T>,其中T是你要返回的Java对象类型。 - Spring MVC会自动使用配置的MessageConverter(如JacksonHttpMessageConverter)将对象序列化为JSON,无需在对象上使用任何注解。
- 可以通过
ResponseEntity的builder方法设置自定义的头部和状态码。
- 在Controller方法中,返回
-
示例代码:
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ResponseEntityController { @GetMapping("/user/entity") public ResponseEntity<User> getUserByEntity() { User user = new User("李四", 25, "lisi@example.com"); // 可以添加自定义headers // return ResponseEntity.ok() // .header("Custom-Header", "value") // .body(user); return ResponseEntity.ok(user); // 简单写法,状态码默认200 } @GetMapping("/user/entity/notfound") public ResponseEntity<User> getUserNotFound() { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); } } // User类同上,无注解 -
优缺点:
- 优点: 仍能利用Spring MVC的自动转换机制,无需在POJO上注解,可以灵活控制响应。
- 缺点: 需要Spring MVC环境,比直接使用
@ResponseBody多一层封装。
使用Map或JSONObject构建JSON结构
如果返回的数据结构相对简单或动态,可以使用Map或第三方库的JSONObject/JSONArray来手动构建JSON结构,然后序列化。
-
步骤:
- 创建
Map或JSONObject实例。 - 手动向其中添加键值对,值可以是基本类型、字符串、List、嵌套的Map/JSONObject等。
- 使用JSON库将
Map或JSONObject序列化为JSON字符串。 - 通过
@ResponseBody或原生Servlet方式返回。
- 创建
-
示例代码(使用Gson的JsonObject和
@ResponseBody):import com.google.gson.JsonObject; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class JsonObjectController { @GetMapping("/user/jsonobject") public String getUserByJsonObject() { // 1. 构建JsonObject JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("name", "王五"); jsonObject.addProperty("age", 28); jsonObject.addProperty("email", "wangwu@example.com"); // 2. 转换为JSON字符串 (Gson的JsonObject本身就是JSON结构,直接toString即可) // 如果使用Jackson的ObjectMapper,也可以 objectMapper.writeValueAsString(jsonObject) return jsonObject.toString(); } @GetMapping("/user/map") public String getUserByMap() { // 使用Map + Jackson/Gson java.util.Map<String, Object> map = new java.util.HashMap<>(); map.put("name", "赵六"); map.put("age", 35); map.put("email", "zhaoliu@example.com"); // 嵌套结构 java.util.Map<String, Object> address = new java.util.HashMap<>(); address.put("city", "北京"); address.put("district", "朝阳区"); map.put("address", address); // 使用Jackson序列化Map // return new ObjectMapper().writeValueAsString(map); // 使用Gson序列化Map // return new Gson().toJson(map); // 此处假设已配置好MessageConverter,直接返回Map会被自动转为JSON(前提是项目有JSON库且配置了转换器) // 这里我们手动调用了toString或序列化,所以不算完全依赖自动转换 // 更纯粹的是直接返回Map,让Spring的MappingJacksonHttpMessageConverter处理 return map.toString(); // 注意:Map的toString不是JSON格式,这里仅为演示,实际需用JSON库序列化 } }注意:直接返回
Map给Spring MVC方法(并期望其转为JSON)通常需要配置好MappingJacksonHttpMessageConverter,此时底层还是用Jackson序列化,只是你不需要在POJO上注解,但手动调用toString()的Map不会生成JSON。 -
优缺点:
- 优点: 灵活性高,适合构建动态、不固定的JSON结构。
- 缺点: 需要手动构建JSON结构,对于复杂对象可能不如直接传递POJO方便;容易出错,如类型不匹配、拼写错误等。
配置自定义的ObjectMapper(间接影响,但POJO无注解)
虽然这种方式不是直接“不用注解传递数据”,但它可以通过全局配置ObjectMapper的行为,使得POJO即使没有注解也能按照预期序列化,设置属性命名策略、忽略未知属性、日期格式等。
- 步骤:
- 创建一个配置类(如
JacksonConfig)。 - 定义一个
@Bean方法
- 创建一个配置类(如



还没有评论,来说两句吧...