Best Practices for Backend API Design and Controller Conventions with AOP in Java
The article explains common pitfalls in Java backend interface design, proposes a unified ResultBean response format, outlines controller coding standards, and demonstrates how to use Spring AOP for logging and exception handling, providing complete code examples and configuration snippets.
In backend development, defining clear and consistent APIs is essential; the article lists frequent mistakes such as inconsistent return formats, ignoring failure cases, including irrelevant or overly complex parameters, and not returning necessary data.
Incorrect examples:
@PostMapping("/delete")
public Map<String, Object> delete(long id, String lang) { }
@PostMapping("/delete")
public Object delete(long id, String lang) {
try {
boolean result = configService.delete(id, local);
return result;
} catch (Exception e) {
log.error(e);
return e.toString();
}
}
@PostMapping("/update")
public void update(long id, xxx) { }
@PostMapping("/delete")
public Map<String, Object> delete(long id, String lang, String userId) { }
@PostMapping("/update")
public Map<String, Object> update(long id, String jsonStr) { }
@PostMapping("/add")
public boolean add(xxx) {
return configService.add();
}To avoid these issues, the article recommends using a unified response wrapper ResultBean (or PageResultBean) and defining dedicated request/response beans.
ResultBean definition:
@Data
public class ResultBean<T> implements Serializable {
private static final long serialVersionUID = 1L;
public static final int SUCCESS = 0;
public static final int FAIL = 1;
public static final int NO_PERMISSION = 2;
private String msg = "success";
private int code = SUCCESS;
private T data;
public ResultBean() {}
public ResultBean(T data) { this.data = data; }
public ResultBean(Throwable e) {
this.msg = e.toString();
this.code = FAIL;
}
}The controller conventions include:
All methods return ResultBean / PageResultBean only.
Never pass these wrappers to service layers.
Avoid returning raw Map or JSON objects from services.
Do not expose HttpServletRequest/Response in method signatures.
Logging should be handled in AOP, not manually in each controller.
Controller AOP implementation (logging and exception handling):
public class ControllerAOP {
private static final Logger logger = LoggerFactory.getLogger(ControllerAOP.class);
public Object handlerControllerMethod(ProceedingJoinPoint pjp) {
long startTime = System.currentTimeMillis();
ResultBean<?> result;
try {
result = (ResultBean<?>) pjp.proceed();
logger.info(pjp.getSignature() + " use time:" + (System.currentTimeMillis() - startTime));
} catch (Throwable e) {
result = handlerException(pjp, e);
}
return result;
}
private ResultBean<?> handlerException(ProceedingJoinPoint pjp, Throwable e) {
ResultBean<?> result = new ResultBean<>();
if (e instanceof CheckException) {
result.setMsg(e.getLocalizedMessage());
result.setCode(ResultBean.FAIL);
} else if (e instanceof UnloginException) {
result.setMsg("Unlogin");
result.setCode(ResultBean.NO_LOGIN);
} else {
logger.error(pjp.getSignature() + " error ", e);
result.setMsg(e.toString());
result.setCode(ResultBean.FAIL);
}
return result;
}
}XML configuration for the AOP aspect:
<aop:aspectj-autoproxy />
<beans:bean id="controllerAop" class="xxx.common.aop.ControllerAOP" />
<aop:config>
<aop:aspect id="myAop" ref="controllerAop">
<aop:pointcut id="target" expression="execution(public xxx.common.beans.ResultBean *(..))" />
<aop:around method="handlerControllerMethod" pointcut-ref="target" />
</aop:aspect>
</aop:config>By enforcing a unified ResultBean format, developers can simplify AOP usage, ensure consistent error handling, and improve code readability and testability across the backend system.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
