Dao接口和实现类以及Service接口和实现类代码抽取

本文介绍了一种针对无线点餐系统的DAO层设计方法,通过抽象基类BaseDao实现CRUD操作,减少代码重复,并展示了具体的BoardDao与CuisineDao实现细节。

紧接着上次无线点餐项目的文档,我们进行Dao层抽取。

6.Dao接口以及实现类代码抽取

对于BoardDaoCuisineDao的处理接口和实现类,除了定义自己的特有方法外,其他基本功能的CRUD方法都一样,只是操作的实体对象不一样。为了代码的复用,简化代码,我们可以将公共的CRUD方法提取到BaseDao中,只需要实现接口即可。

同理不同的实现类,实现CRUD相同的业务逻辑的时除了操作的实体不同,其他都是相同的所以我们可以把相同的业务逻辑实现,抽取出来,放到BaseSericeImpl其他的业务逻辑实现继承BaseSericeImpl即可

抽取原理图如下:

 

6.1 BaseDao的代码为:

/**

 * 通用BaseDao数据操作接口

 * 

 * @author Leo.Chen

 * 

 * @param <T>

 */

public interface BaseDao<T> {

/**

 * 保存一个对象

 * 

 * @param t

 */

public void save(T t);

 

/**

 * 删除一个对象

 * 

 * @param id

 */

public void delete(int id);

 

/**

 * 删除一个对象

 * 

 * @param t

 */

public void update(T t);

 

/**

 * 查询所有

 * 

 * @return

 */

public List<T> queryAll();

}

6.2 BaseDaoImpl代码为:

我们在没有使用框架Hibernate的情况下,使用JDBC技术来操作数据库时候需要自己手写SQL语句,因此为了避免dao代码的复杂性,不适用反射技术,因此我们只是把各个模块公共的代码抽取到BaseDaoImpl中,该类还是抽象的,让其子类具体再实现。

因此通用的BaseServiceImpl实现类代码如下:

/**

 * 通用Dao接口实现类

 * @author Leo.Chen

 * @param <T>

 */

public abstract class BaseDaoImpl<T> implements BaseDao<T> {

protected QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());

}

6.3 BoardDao接口的代码为:

/**

 * 餐桌管理持久化数据操作接口

 * @author Leo.Chen

 */

public interface BoardDao extends BaseDao<Board> {

}

6.4 BoardDaoImpl实现类的代码为:

public class BoardDaoImpl extends BaseDaoImpl<Board> implements BaseDao<Board>, BoardDao {

 

@Override

public void save(Board board) {

// 建立sql语句

String excuteSql = "insert into t_board(bName,isBook,bookTime) values (?,?,?)";

// 封装参数

Object[] param = { board.getbName(), board.getIsBook(), board.getBookTime() };

try {

// 执行sql语句

runner.update(excuteSql, param);

catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

 

@Override

public void delete(int id) {

String excuteSql = "delete from t_board where bid=?";

try {

runner.update(excuteSql, id);

catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

 

@Override

public void update(Board board) {

String excuteSql = "update t_board b set b.bname=?, b.isBook=?, b.bookTime=? where b.bid=?";

Object[] param = { board.getbName(), board.getIsBook(), board.getBookTime(), board.getBid()};

try {

runner.update(excuteSql, param);

catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

 

@Override

public List<Board> queryAll() {

String sql = "select * from t_board";

List<Board> resultList = null;

try {

resultList = runner.query(sql, new BeanListHandler<Board>(Board.class));

catch (SQLException e) {

e.printStackTrace();

resultList = new ArrayList<Board>();

}

return resultList;

}

}

6.5 CuisineDao接口的代码为:

public interface CuisineDao extends BaseDao<Cuisine> {

/**

 * 根据菜系名称模糊查询

 * @param cid

 * @return

 */

public List<Cuisine> queryByName(String name);

}

6.6 CuisineDaoImpl实现类代码为:

public class CuisineDaoImpl extends BaseDaoImpl<Cuisine> implements CuisineDao {

@Override

public void save(Cuisine cuisine) {

try {

String sql = "insert into t_cuisine (name) values(?)";

runner.update(sql, cuisine.getName());

catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

 

@Override

public void delete(int id) {

try {

String sql = "delete from t_cuisine where cid=?";

runner.update(sql, id);

catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

 

@Override

public void update(Cuisine cuisine) {

try {

String sql = "update t_cuisine c set c.name=? where c.cid=?";

runner.update(sql, cuisine.getName(), cuisine.getCid());

catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

     @Override

public List<Cuisine> queryAll() {

String sql = "select * from t_cuisine";

List<Cuisine> resultList = null;

try {

resultList = runner.query(sql, new BeanListHandler<Cuisine>(Cuisine.class));

catch (SQLException e) {

e.printStackTrace();

resultList = new ArrayList<Cuisine>();

}

return resultList;

}

 

 

@Override

public List<Cuisine> queryByName(String name) {

List<Cuisine> resultList = null;

try {

String sql = "select * from t_cuisine where name like '%"+name+"%'";

resultList = runner.query(sql, new BeanListHandler<Cuisine>(Cuisine.class));

catch (SQLException e) {

e.printStackTrace();

resultList = new ArrayList<Cuisine>();

}

return resultList;

}

}

7.餐桌和菜系的Service实现

Service中同样的采取Dao中的抽取设计,将公共的Service方法抽取到BaseService中。在BaseService接口中抽取公共的调用DaoCRUD方法,其他接口只需要继承即可。

Service的抽取原理图:

 

7.1BaseService代码如下:

/**

 * 通用Service接口

 * @author Leo.Chen

 * @param <T>

 */

public interface BaseService<T> {

/**

 * 保存对象

 * 

 * @param t

 */

public void save(T t);

 

/**

 * 删除对象

 * 

 * @param id

 */

public void delete(int id);

 

/**

 * 更新对象

 * 

 * @param t

 */

public void update(T t);

 

/**

 * 获取所有

 * 

 * @return

 */

public List<T> queryAll();

}

7.2BaseServiceImpl代码如下:

/**

 * 通用Service实现类

 * 

 * @author Leo.Chen

 * 

 * @param <T>

 */

public abstract class BaseServiceImpl<T> implements BaseService<T> {

/**

 * 将所有操作数据库的Dao对象在BaseServiceImpl中实例化,自身模块的Service只需要继承该类即可

 */

protected BoardDao boardDao = BeanFactoryUtil.getInstance().createBean(BoardDao.class);

protected CuisineDao cuisineDao = BeanFactoryUtil.getInstance().createBean(CuisineDao.class);

}

7.3餐桌Service实现

BoardService接口代码如下:

public interface BoardService extends BaseService<Board> {

}

BoardServiceImpl接口代码如下:

public class BoardServiceImpl extends BaseServiceImpl<Board> implements

BoardService {

 

@Override

public void save(Board t) {

boardDao.save(t);

}

 

@Override

public void delete(int id) {

boardDao.delete(id);

}

 

@Override

public void update(Board t) {

boardDao.update(t);

}

 

@Override

public List<Board> queryAll() {

List<Board> boards = boardDao.queryAll();

if (boards.size() != 0) {

return boards;

}

return null;

}

}

7.4菜系Service实现

CuisineService接口代码如下:

public interface CuisineService extends BaseService<Cuisine> {

/**

 * 根据名称查询菜系

 * @param name

 * @return

 */

public List<Cuisine> queryByName(String name);

}

 

CuisineServiceImpl实现类代码如下:

public class CuisineServiceImpl extends BaseServiceImpl<Cuisine> implements CuisineService{

 

@Override

public void save(Cuisine t) {

cuisineDao.save(t);

}

 

@Override

public void delete(int id) {

cuisineDao.delete(id);

}

 

@Override

public void update(Cuisine t) {

cuisineDao.update(t);

}

 

@Override

public List<Cuisine> queryAll() {

List<Cuisine> cuisines = cuisineDao.queryAll();

if (cuisines.size() != 0) {

return cuisines;

}

return null;

}

 

@Override

public List<Cuisine> queryByName(String name) {

List<Cuisine> cuisines = cuisineDao.queryByName(name);

if (cuisines.size() != 0) {

return cuisines;

}

return null;

}

}



<think>嗯,用户问的是SpringMVC中如何分设计对外接口内部业务接口的规范。我需要先理清楚这两个概念的区别。对外接口通常是给外部系统调用的,比如API给客户端或者第三方使用,而内部业务接口可能是系统内部模块之间的调用。 首先,用户可能希望了解如何将这两种接口代码结构上分开,避免混在一起。常见的做法可能是通过不同的包结构来隔离,比如在controller包下创建externalinternal子包,分别存放对外对内的控制器。这样结构清晰,也方便管理权限日志等不同的处理逻辑。 然后,考虑到对外接口可能需要更严格的安全措施,比如身份验证、参数校验、限流等,而内部接口可能更注重效率。这时候可能需要使用Spring的拦截器或者过滤器,针对不同的接口路径应用不同的处理逻辑。比如,对外接口的URL统一以/api/external开头,内部接口用/api/internal,这样在配置拦截器时可以区分开来。 另外,返回的数据格式也需要统一。对外接口通常需要封装成固定的格式,比如包含code、message、data字段,而内部接口可能直接返回业务对象。这时候可以使用@ControllerAdvice或者自定义的ResponseBodyAdvice来统一处理响应体,确保对外接口的返回结构一致。 还有版本控制的问题,对外接口可能会有版本迭代的需求,比如在URL中添加/v1/路径,而内部接口可能不需要版本控制。这也需要在路由设计时考虑到,方便后续升级维护。 用户可能还关心如何避免代码重复,比如公共的业务逻辑如何抽取。这时候可以引入服务,将业务逻辑封装在service,无论是外部还是内部控制器都调用相同的service方法,避免冗余代码。 另外,文档管理也很重要,对外接口可能需要使用Swagger等工具生成API文档,而内部接口可能不需要公开。可以通过配置不同的Docket来分别管理,确保外部文档清晰,内部接口文档适当保密。 最后,异常处理方面,对外接口可能需要将异常转换为用户友好的错误信息,而内部接口可能直接抛出详细错误。全局异常处理器可以根据请求路径来决定返回的错误格式,提升外部接口的友好性。 总结一下,分设计的核心在于分离关注,通过包结构、路由策略、统一响应、安全控制、服务抽象等方面来实现内外接口的隔离规范化管理,同时保持代码的可维护性扩展性。</think># SpringMVC控制器对外接口与内部业务接口设计规范 ## 一、分架构设计 推荐采用五架构模式实现接口隔离: ``` src/main/java ├── controller │ ├── external // 对外接口控制器 │ └── internal // 内部业务接口控制器 ├── service │ ├── api // 接口抽象 │ └── impl // 业务实现 ├── dao └── model ├── dto // 对外传输对象 └── vo // 内部视图对象 ``` ## 二、接口定义规范 1. **路径隔离策略** - 对外接口:`@RequestMapping("/api/external/v1/...")` - 内部接口:`@RequestMapping("/api/internal/v1/...")` 2. **协议区分** ```java // 对外接口示例 @RestController @RequestMapping("/api/external/v1/order") public class ExternalOrderController { @PostMapping("/create") public ResponseDTO<OrderResult> createOrder(@Valid @RequestBody OrderCreateDTO dto) { // 调用服务接口 } } ``` ## 三、安全控制策略 1. 对外接口必须配置安全拦截器: ```java @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/api/external/**") .addFilterBefore(new SignAuthFilter(), UsernamePasswordAuthenticationFilter.class) .addFilter(new RateLimitFilter()); } } ``` ## 四、数据传输规范 1. 对象隔离策略: ```java // 对外DTO对象示例 public class OrderCreateDTO { @NotBlank @ApiModelProperty("订单编号") private String orderNo; @Min(1) private Integer quantity; } // 内部VO对象示例 public class OrderVO { private Long id; private BigDecimal actualPrice; } ``` ## 五、服务抽象 建议通过接口隔离实现业务逻辑复用: ```java public interface OrderService { OrderVO createOrder(OrderCreateDTO dto); } @Service public class OrderServiceImpl implements OrderService { // 统一业务逻辑实现 } ``` ## 六、响应格式统一 使用`@ControllerAdvice`实现响应包装: ```java @ControllerAdvice(basePackages = "com.example.controller.external") public class ExternalResponseWrapper implements ResponseBodyAdvice<Object> { @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { return ResponseDTO.success(body); } } ``` ## 七、文档管理规范 使用Swagger分组管理: ```java @Bean public Docket externalApi() { return new Docket(DocumentationType.SWAGGER_2) .groupName("external") .select() .apis(RequestHandlerSelectors.basePackage("com.example.controller.external")) .build(); } ``` ## 最佳实践建议 1. 对外接口响应时间应控制在300ms以内[^1] 2. 内部接口调用建议添加熔断机制 3. 使用API网关进行流量管控 4. 对外接口版本号必须遵循语义化版本规范(SemVer)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Seven的代码实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值