Tags: Tax Service System project


Extracting BaseService

So far, we have written the development of three modules. Now that we’ve extracted BaseAction and BaseDao, let’s look at our Service interface.

  • UserService


/** * created by ozc on 2017/5/23. */
public interface UserService {

    / / new
    void save(User user);

    / / update
    void update(User user);

    // Delete by id
    void delete(Serializable id);

    // Find by id
    User findObjectById(Serializable id);

    // Find the list
    List<User> findObjects(a) throws ServiceException;

    // Export the user list
    void exportExcel(List<User> userList, ServletOutputStream outputStream);

    // Import the user list
    void importExcel(File userExcel, String userExcelFileName);

    /** * Query user ** by account and user ID@paramId User ID *@paramAccount User account *@returnUser list */
    List<User> findAccount(String id, String account);

    void saveUserAndRole(User user, String[] userRoleIds);

    // Get the role of the user from the user ID
    List<UserRole> findRoleById(String id);

    void deleteUserRoleById(String[] userRoleIds);

    List<User> findUserByAccountAndPassword(String account, String password);
}

Copy the code
  • InfoService

/** * created by ozc on 2017/5/23. */
public interface InfoService {

    / / new
    public void save(Info info);
    / / update
    public void update(Info info);
    // Delete by id
    public void delete(Serializable id);
    // Find by id
    public Info findObjectById(Serializable id);
    // Find the list
    public List<Info> findObjects(a) ;
}

Copy the code
  • RoleService

/** * Created by ozc on 2017/5/26. */
public interface RoleService {

    / / new
     void save(Role role);
    / / update
     void update(Role role);
    // Delete O based on id
     void delete(Serializable id);
    // Find by id
     Role findObjectById(Serializable id);
    // Find the list
     List<Role> findObjects(a)  ;

}

Copy the code

We can see that there are methods of add, delete, modify and review in ** three Service interfaces, which is obviously duplicate code. ** Therefore, we need to extract them into a BaseService.

Extracting BaseService

Add the service package to the core module to extract the BaseService


package zhongfucheng.core.service;

import java.io.Serializable;
import java.util.List;

/** * Created by ozc on 2017/6/7. */
interface BaseService<T> {
    / / new
    void save(T entity);

    / / update
    void update(T entity);

    // Delete by id
    void delete(Serializable id);

    // Find by id
    T findObjectById(Serializable id);

    // Find the list
    List<T> findObjects(a);
}

Copy the code
  • Extracting BaseServiceImpl

Our Sercive implements methods by calling objects in the DAO layer. Since this Service represents the entire project, BaseDao should be used


package zhongfucheng.core.service.impl;

import zhongfucheng.core.dao.BaseDao;
import zhongfucheng.core.service.BaseService;

import java.io.Serializable;
import java.util.List;

/** * Created by ozc on 2017/6/7. */

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

    // Use BaseDao to manipulate the database
    private BaseDao<T> baseDao;

    @Override
    public void save(T entity) {
        baseDao.save(entity);

    }

    @Override
    public void update(T entity) {
        baseDao.update(entity);

    }

    @Override
    public void delete(Serializable id) {
        baseDao.delete(id);

    }
    @Override
    public T findObjectById(Serializable id) {
        return baseDao.findObjectById(id);
    }

    @Override
    public List<T> findObjects(a) {
        returnbaseDao.findObjects(); }}Copy the code

Take the Info module for example

  • InfoService

InfoService inherits the BaseService interface, so there is a way to add, delete, change, and check. At the same time, determine the type of the generic T.


	/** * created by ozc on 2017/5/23. */
	public interface InfoService extends BaseService<Info> {}Copy the code
  • InfoServiceImpl

InfoService is inherited, and there are methods to add or delete the query, but the specific operations are implemented in BaseServiceImpl. We inherit it and give the corresponding type of the generic T.


@Service
public class InfoServiceImpl extends BaseServiceImpl<Info> implements InfoService {}Copy the code

What’s the problem now?? We use the BaseDao variable in BaseServiceImpl to operate on the database. There is no BaseDao variable in BaseServiceImpl.

First, to be clear, we cannot inject BaseDao into BaseServiceImpl because BaseServiceImpl is itself an abstract class. So how do we instantiate BaseDao?

We can do this:

  • The InfoServiceImpl itself needs to inject the InfoDao to perform operations on the database.

  • Instead of using the property input, we use the set method for injection

  • At the same time as the injection, set the BaseDao method in BaseServiceImpl.

  • So when we inject, we can call BaseDao’s set method to pass the object we want to inject.

  • Finally, we have the baseDao variable in BaseServiceImpl.

  • InfoServiceImpl takes the InfoDao object and sets the InfoDao object into BaseServiceImpl.


@Service
public class InfoServiceImpl extends BaseServiceImpl<Info> implements InfoService {

    private InfoDao infoDao;
    @Resource
    public void setInfoDao(InfoDao infoDao) {
        super.setBaseDao(infoDao);
        this.infoDao = infoDao; }}Copy the code
  • BaseServiceImpl sets the set method for BaseDao.
   // Use BaseDao to manipulate the database
    private BaseDao<T> baseDao;
    public void setBaseDao(BaseDao<T> baseDao) {
        this.baseDao = baseDao;
    }

Copy the code

Conditions of the query

Let’s implement the following functions:

The traditional way

In fact, it is also a query, but the query more than a condition. In the traditional way we can do this:

  • Declare a method in BaseDao that receives SQL and a list of parameters

    // Query the list by condition
    List<T> findObjects(String sql, List<Object> objectList);
Copy the code
  • Implement it in Base EDaoimpl

	@Override
	public List<T> findObjects(String sql, List<Object> objectList) {

		Query query = getSession().createQuery(sql);
		if(objectList ! =null) {
			int i =0;
			for (Object o : objectList) {
				query.setParameter(i, o);
				i++;
			}
			return query.list();
		}
		return query.list();
	}
Copy the code
  • BaseService defines it:


    // Query the list by condition
    List<T> findObjects(String sql, List<Object> objectList);

Copy the code
  • It is called using baseDao in BaseServiceImpl

    @Override
    public List<T> findObjects(String sql, List<Object> objectList) {
        return baseDao.findObjects(sql, objectList);
    }
Copy the code
  • Requests are processed in Action

We’ll stick with listUI, because it’s just that the parameters can be different.

  • If the user is using a conditional query, it should have an Info object to bring in.
  • If it is not a conditional query, there is no Info object
  • Query [add new field in HQL statement] according to Info object setting whether to set parameters. So this method is universal.

    public String listUI(a) {

        // Query statement
        String hql = "FROM Info i ";
        List<Object> objectList  = new ArrayList<>();

        // Check whether the query is conditional based on whether info is null. If info is empty, all are queried.
        if(info ! =null) {
            if (StringUtils.isNotBlank(info.getTitle())) {
                hql += "where i.title like ?";
                objectList.add("%" + info.getTitle() + "%");
            }
        }
        infoList = infoServiceImpl.findObjects(hql,objectList);
        ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);
        return "listUI";
    }
Copy the code

To optimize the

Looking back at the code in our Action, we can see some inelegance:

Therefore, we want to optimize the above code with a utility class.

In response to the above problem, we found that handwritten concatenation of SQL is very error-prone. Then we can concatenate in the utility class, use the method to fetch on the line. The e object of the query is written dead, we want to be able to handle any query.

We can find the following patterns:

FROM Info WHERE title like ? and state = ? Order by createTime,state query (QueryHelper) : HQL: from; And it only appears once where clause: optional; But the keyword where appears once; Order by clause: Optional; But the keyword order by appears once; 2, query condition value set: occurrence time: when adding query condition,? Value of the query conditionCopy the code
  • Utility class code:

package zhongfucheng.core.utils;

import java.util.ArrayList;
import java.util.List;

/** * Created by ozc on 2017/6/7. */
public class QueryHelper {

    private String fromClause = "";
    private String whereClause = "";
    private String orderbyClause = "";
    private List<Object> objectList;

    public static String ORDER_BY_ASC = "asc";
    public static String ORDER_BY_DESC = "desc";



    // The FROM clause occurs only once
    /** * build the FROM clause and set which table to query *@paramAClass Specifies the type the user wants to operate on@paramAlias alias * /
    public QueryHelper(Class aClass, String alias) {
        fromClause = " FROM " + aClass.getSimpleName() + "" + alias;
    }
    // Multiple conditions can be added to a WHERE clause, but the WHERE keyword appears only once
    /** * Construct the WHERE clause *@param condition
     * @param objects
     * @return* /
    public QueryHelper addCondition(String condition, Object... objects) {
        // If there are already characters, then the WHERE keyword already exists
        if (whereClause.length() > 0) {
            whereClause += " AND " + condition;
        } else {
            whereClause += " WHERE" + condition;
        }
        // When adding a query condition,? Value of the query condition
        if (objects == null) {
            objectList = new ArrayList<>();
        }

        for (Object object : objects) {
            objectList.add(object);
        }

        return this;
    }
    / * * * *@paramProperty Specifies the property * to be sorted@paramOrder is in ascending or descending order@return* /
    public QueryHelper orderBy(String property, String order) {

        // If there are already characters, then the ORDER keyword already exists
        if (orderbyClause.length() > 0) {
            orderbyClause += "," + property +"" + order;
        } else {
            orderbyClause += " ORDER BY " + property+"" + order;
        }
        return this;
    }

    /** * Returns the HQL statement */
    public String returnHQL(a) {
        return fromClause + whereClause + orderbyClause;
    }

    /** * get the argument list *@return* /
    public List<Object> getObjectList(a) {
        returnobjectList; }}Copy the code
  • The processing of the Action:


    public String listUI(a) {

        QueryHelper queryHelper = new QueryHelper(Info.class, "i");

        // Check whether the query is conditional based on whether info is null. If info is empty, all are queried.
        if(info ! =null) {
            if (StringUtils.isNotBlank(info.getTitle())) {
                queryHelper.addCondition(" i.title like ? "."%" + info.getTitle() + "%");
            }
        }
        queryHelper.orderBy("i.createTime", QueryHelper.ORDER_BY_DESC);

        infoList = infoServiceImpl.findObjects(queryHelper);

        //infoList = infoServiceImpl.findObjects(hql,objectList);
        ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);
        return "listUI";
    }
Copy the code
  • Finally, add a queryHelper parameter to the DAO/Service layer.

conclusion

  • Because the code for Service is too repetitive, we also extract Service. Extract into a BaseService interface
  • BaseServiceImpl implements the BaseService interface, but uses the BaseDao object to call the implemented methods
    • At this point, BaseServiceImpl is an abstract class and cannot be instantiated by itself. So how do you instantiate BaseDao?
    • When our InfoServiceImpl inherits from BaseServiceImpl, we need to use the InfoDao itself to call the module’s business.
    • It is easy to talk to the InfoDao instance in InfoServiceImpl, using autoload, set method injection, and so on. This time we use the set method for injection!
    • What are the benefits of the set method? The InfoServiceImpl can inject InfoDao objects and perform other operations at the same time. For example, call the parent set method!!!!!!!
    • We simply provide a setBaseDao method in BaseServiceImpl, and subclasses pass in their Dao. So our BaseDao is instantiated!
  • Because of the uncertainty of our query condition, we need to concatenate the query condition string. It’s unsafe and error-prone. We encapsulate a query assistant object. Dedicated to queries.

If you find this article helpful, give the author a little encouragement