我正在对返回一个对象列表的方法进行ajax调用,如果在try-catch块中获取数据时发生了某些事情,我会使用response.setStatus(400)
在前面显示错误-最后,我返回的是null,那里是我收到SonarLint通知的地方。现在,如果我将其更改为空集合,则会出现以下错误:
getWriter() has already been called for this response
我认为上面的原因是因为我返回的是空集合,并且http响应状态为400。如果我将其保留为null,那么一切正常,只是SonarLint通知。
@GetMapping("/runquery")
@ResponseBody
public List<Map<String, Object>> runQuery(@RequestParam(name = "queryId") String queryId, @RequestParam(name = "formData") String formData, HttpServletResponse response) throws IOException {
(...)
try {
queryResult = namedParameterJdbcTemplateHive.queryForList(query, paramSource);
for (Map<String, Object> map : queryResult) {
Map<String, Object> newMap = new HashMap<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (key.contains(".")) {
key = key.replace(".", "_");
newMap.put(key, value);
} else {
newMap.put(key, value);
}
}
queryResultFinal.add(newMap);
}
} catch (Exception e) {
response.setStatus(400);
response.getWriter().write(e.getMessage());
return null; <-- SonarLint notification
}
return queryResultFinal;
}
关于如何解决此通知的任何想法?
答案 0 :(得分:1)
我建议不要在此方法中捕获异常,而是将其抛出,并在控制器中使用exception handler method来处理它。在这种情况下,您将永远不会从方法中返回null
,Sonar将无可抱怨。这也意味着您正在以设计使用方式使用Spring。
例如,如下所示:
@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleException(Exception e) {
log.error("Exception during request", e);
}
或您当前处理的直接等效项:
@ExceptionHandler
public ResponseEntity<?> handleException(Exception e) {
return ResponseEntity.badRequest().body(e.getMessage()).build();
}
切换到异常处理程序后,可以从常规方法中删除HttpServletResponse response
参数。
答案 1 :(得分:0)
我建议您创建一个包含所有响应的 GenericReponse ,这对于前端也非常有用,因为您面对的是固定模板。
因此,通过此解决方案,您可以包装所需的任何对象并将其发送给响应。
我对这种情况进行了编码:
1-创建GenericResponse类
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class GenericResponse {
private Boolean error;
private List<ErrorPayload> errorPayload;
private Object payload;
public GenericResponse(Boolean error) {
this.error = error;
}
public static GenericResponse ok() {
return new GenericResponse(false);
}
public GenericResponse payload(Serializable o) {
this.payload = o;
return this;
}
//Getters and Setters and other Constructors
2-创建ErrorPayload类
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorPayload {
private String errorMessage;
private String errorType;
//Getters and Setters and Constructors
}
3-创建ExceptionConverter服务(有异常时使用)
@Service
public class ExceptionConverterService {
public GenericResponse convert(Exception x) {
GenericResponse genericResponse = new GenericResponse();
genericResponse.setError(true);
String exceptionType = x.getClass().getSimpleName();
String exceptionMessage = x.getClass().getSimpleName();
genericResponse.setErrorPayload(Collections.singletonList(new ErrorPayload(exceptionType, exceptionMessage)));
return genericResponse;
}
}
4-使用GenericResponse更改您的方案
您需要做的是:
List<Map<String, Object>>
更改为GenericResponse
GenericResponse
我如下更改了您的代码(只需更改3行)
@RestController
public class TestController {
@Autowired
private ExceptionConverterService exceptionConverter;
@GetMapping("/runquery")
@ResponseBody
//Changed (Change Return type to GenericResponse )
public GenericResponse runQuery(@RequestParam(name = "queryId") String queryId, @RequestParam(name = "formData") String formData, HttpServletResponse response) throws IOException {
try {
//Your code
}
} catch (Exception e) {
//Changed (Create GenericResponse for Exception)
GenericResponse genericResponse = exceptionConverter.convert(e);
return genericResponse;
}
//Changed (Create GenericResponse for main result)
return GenericResponse.ok().payload(queryResultFinal);
}
}
两种情况的示例(第一种无例外,第二种无例外)
示例1
带有GenericResponse的控制器(此示例中我们没有例外)
@RestController
public class TestController {
@GetMapping(value = "/getNameAndFamily")
public GenericResponse getNameAndFamily() {
Map<String, String> person = new HashMap<>();
person.put("name", "foo");
person.put("family", "bar");
return GenericResponse.ok().payload((Serializable) person);
}
}
结果如下:
{
"error": false,
"payload": {
"name": "foo",
"family": "bar"
}
}
示例2
当我们在业务中遇到异常时,带有GenericResponse的控制器
@RestController
public class TestController {
@Autowired
private ExceptionConverterService exceptionConverter;
@GetMapping(value = "/getNameAndFamily")
public GenericResponse getNameAndFamily() {
try {
//Create Fake Exception
int i = 1 / 0;
return GenericResponse.ok();
} catch (Exception e) {
//Handle Exception
GenericResponse genericResponse = exceptionConverter.convert(e);
return GenericResponse.ok().payload((Serializable) genericResponse);
}
}
}
结果如下:
{
"error": true,
"errorPayload": [
{
"errorType": "ArithmeticException"
}
]
}