spring boot基础搭建(三)

接到上一篇:Spring Boot基础搭建(二)


重新配置hibernate:

在config包下创建HibernateConfiguration类如下:

代码:

package com.config;


import org.hibernate.SessionFactory;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.orm.hibernate5.HibernateTransactionManager;

import org.springframework.orm.hibernate5.LocalSessionFactoryBean;


import javax.sql.DataSource;

import java.util.Properties;


/**

* Created by onion on 2017-03-30 15:18.

*/

@Configuration

public class HibernateConfiguration {


  //配置sessionFactory

  @Bean

  public LocalSessionFactoryBean sessionFactory(@Qualifier("dataSource") DataSource dataSource,

                                                @Value("${spring.hibernate.packageScan}") String packageScan,

                                                @Value("${spring.jpa.properties.hibernate.dialect}") String dialect,

                                                @Value("${spring.jpa.show-sql}") String showSql,

                                                @Value("${spring.jpa.properties.hibernate.format_sql}") String formatSql,

                                                @Value("${spring.jpa.properties.hibernate.use_sql_comments}") String useSqlComments,

                                                @Value("${spring.jpa.hibernate.ddl-auto}") String ddlAuto) {

      LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();

      localSessionFactoryBean.setDataSource(dataSource);

      localSessionFactoryBean.setPackagesToScan(packageScan);

      Properties properties = new Properties();

      properties.setProperty("hibernate.dialect", dialect);

      properties.setProperty("hibernate.show_sql", showSql);

      properties.setProperty("hibernate.format_sql", formatSql);

      properties.setProperty("hibernate.use_sql_comments", useSqlComments);

      properties.setProperty("hibernate.hbm2ddl.auto", ddlAuto);

      localSessionFactoryBean.setHibernateProperties(properties);

      return localSessionFactoryBean;

  }


  //配置hibernate事务处理

  @Bean

  public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {

      HibernateTransactionManager transactionManager = new HibernateTransactionManager();

      transactionManager.setSessionFactory(sessionFactory);

      return transactionManager;

  }


}


然后在application.properties添加以下代码:

spring.jta.transaction-manager-id=transactionManager

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

spring.hibernate.packageScan=com.tgb.model


将UserService代码修改为:

package com.tgb.service;


import com.tgb.dao.UserDao;

import com.tgb.model.User;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;


import java.util.List;


/**

* Created by onion on 2017-03-28 09:11.

*/

@Service

@Transactional(rollbackFor = Exception.class)

public class UserService {

  @Autowired

  private UserDao userDao;


  public User addUser(User user) {

      User user1 = new User();

      user1.setName("测试数据");

      user1.setAge(2);

      userDao.save(user1);

      int i = 10/0;

      return userDao.save(user);

  }


  @Transactional(readOnly = true)

  public List<User> getAll() {

      return userDao.findAll();

  }

}

上面的Transactional(rollbackFor = Exception.class)注解是设置事务处理。

在addUser方法中我们int i = 10/0 会出现异常。当出现异常信息时候我们实现了数据回滚。

启动服务访问http://localhost:8080/addUser.html添加一个用户我们可以看到数据库里面没有出现异常前添加的User说明没有问题。


在dao包下新建impl包,如下:

在dao包下新建GenericDao类,如下:

其中代码:

package com.tgb.dao;


import java.util.List;


/**

* Created by onion on 2017-03-30 15:57.

*/

public interface GenericDao<T, PK> {


  void save(T entity);


  void delete(T entity);


  void deleteAll(List<T> entities);


  void saveOrUpdate(T entity);


  T findById(PK id);


  void update(T entity);


  List<T> findAll(Object... args);


  Object getUniqueObject(String hql, Object... params);


  List<T> findAllbyhql(String hql);


  void deletebyhql(String hql);


  List<T> queryPage(T entity, int page, int rows);


}

在dao.impl下创建类GenericDaoImpl,如下:

代码:

package com.tgb.dao.impl;


import com.tgb.dao.GenericDao;

import org.hibernate.HibernateException;

import org.hibernate.Query;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.orm.hibernate5.HibernateCallback;

import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import java.io.Serializable;

import java.lang.reflect.ParameterizedType;

import java.util.List;


/**

* Created by onion on 2017-03-30 15:59.

*/

public class GenericDaoImpl <T, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK> {


  @Autowired

  public void InitSession(SessionFactory sessionFactory) {

      setSessionFactory(sessionFactory);

  }


  private Class<T> clazz;


  public GenericDaoImpl() {

      clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

  }


  @Override

  public void save(T entity) {

      getHibernateTemplate().save(entity);

  }


  @Override

  public T findById(PK id) {

      return getHibernateTemplate().get(clazz, id);

  }


  @Override

  public void update(T entity) {

      getHibernateTemplate().update(entity);

  }


  @Override

  public void saveOrUpdate(T entity) {

      getHibernateTemplate().saveOrUpdate(entity);

  }


  @Override

  public void delete(T entity) {

      getHibernateTemplate().delete(entity);

  }


  @Override

  public void deleteAll(List<T> entities) {

      getHibernateTemplate().deleteAll(entities);

  }


  @Override

  public List<T> findAll(Object... args) {

      return (List<T>) getHibernateTemplate().find("from " + clazz.getName(), args);

  }


  @Override

  public List<T> queryPage(T entity, int page, int rows) {

      return getHibernateTemplate().findByExample(entity, (page - 1) * rows, rows);

  }



  @Override

  public List<T> findAllbyhql(String hql) {

      return (List<T>) getHibernateTemplate().find(hql);

  }


 

  @Override

  public Object getUniqueObject(final String hql, final Object... params) {

      Object result = null;

      result = getHibernateTemplate().executeWithNativeSession(new HibernateCallback() {

          public Object doInHibernate(Session session) throws HibernateException {

              Query query = session.createQuery(hql);

              if (params != null) {

                  for (int i = 0; i < params.length; i++) {

                      query.setParameter(i, params[i]);

                  }

              }

              return query.uniqueResult();

          }

      });

      return result;

  }


  @Override

  public void deletebyhql(final String hql) {

      getHibernateTemplate().executeWithNativeSession(new HibernateCallback() {

          public Object doInHibernate(Session session) throws HibernateException {

              session.createQuery(hql).executeUpdate();

              return 1;

          }

      });

  }

}

修改UserDao代码如下:

package com.tgb.dao;


import com.tgb.model.User;

/**

* Created by onion on 2017-03-28 09:07.

*/

public interface UserDao extends GenericDao<User,Long> {


}

在dao.impl下创建UserDaoImpl类,如下:

代码:

package com.tgb.dao.impl;


import com.tgb.dao.UserDao;

import com.tgb.model.User;

import org.springframework.stereotype.Repository;


/**

* Created by onion on 2017-03-30 16:03.

*/

@Repository

public class UserDaoImpl extends GenericDaoImpl<User,Long> implements UserDao{


}


在override包下创建LocalNameingStrategy类,如下:

代码:

package com.utils.override;


import org.hibernate.boot.model.naming.Identifier;

import org.hibernate.boot.model.naming.PhysicalNamingStrategy;

import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;


/**

* Created by onion on 2017-03-30 16:27.

*/

public class LocalNamingStrategy implements PhysicalNamingStrategy {


  @Override

  public Identifier toPhysicalCatalogName(Identifier identifier, JdbcEnvironment jdbcEnvironment) {

      return convert(identifier);

  }


  @Override

  public Identifier toPhysicalSchemaName(Identifier identifier, JdbcEnvironment jdbcEnvironment) {

      return convert(identifier);

  }


  @Override

  public Identifier toPhysicalTableName(Identifier identifier, JdbcEnvironment jdbcEnvironment) {

      return convert(identifier);

  }


  @Override

  public Identifier toPhysicalSequenceName(Identifier identifier, JdbcEnvironment jdbcEnvironment) {

      return convert(identifier);

  }


  @Override

  public Identifier toPhysicalColumnName(Identifier identifier, JdbcEnvironment jdbcEnvironment) {

      return convert(identifier);

  }


  private Identifier convert(Identifier identifier) {

      if (identifier == null) {

          return identifier;

      }

      String newName = identifier.getText();

      return Identifier.toIdentifier(newName);

  }

}

这个接口是在服务启动时候hibernate缓存数据库字段前可以调用的接口。newName就是当前的字段名称,可以根据业务去在缓存前修改表字段,比如加前后缀之类的。

然后把它配置到hibernate中。


在HibernateConfiguration中的sessionFactory方法的localSessionFactoryBean.setPackagesToScan(packageScan);

下面添加代码:

localSessionFactoryBean.setPhysicalNamingStrategy(new LocalNamingStrategy());


在override包下新建QueryResInterceptor类如下:

代码:

package com.utils.override;


import org.hibernate.EmptyInterceptor;


/**

* Created by onion on 2017-03-30 16:36.

*/

public class QueryResInterceptor extends EmptyInterceptor {


  @Override

  public String onPrepareStatement(String sql) {

      return super.onPrepareStatement(sql);

  }

}

上面的方法是hibernate在执行sql之前会调用的接口,我们可以通过这个方法去动态修改表名称或字段名称,比如每个月给表加上后缀年月份等等,可以实现一些业务上面定期换表的功能。


在HibernateConfiguration中的sessionFactory方法的localSessionFactoryBean.setPackagesToScan(packageScan);

下面添加代码:

localSessionFactoryBean.setEntityInterceptor(new QueryResInterceptor());


可以在刚刚添加到两个类中输出newName和sql。启动和执行sql的时候可以看到配置成功。

GenericDaoImpl实现了使用sessionFactory去执行hql,里面写了一些基础的方法,分页查询可以自己通过拼接hql完成,不会的可以查一下。

。。。。。。。。。。。。。。。。。。。。。。。。。。。

到此hibernate的配置就成功了。


配置jdbctemplate直接执行sql:

hibernate虽然有sql的回调方法,但是在hibernate中写sql总是感觉很奇怪,也比较麻烦,所以我们配置spring jdbc提供给我们的sql执行类去执行sql。


在utils包下创建JdbcUtils,如下:

代码:

package com.utils;


import org.springframework.jdbc.core.JdbcTemplate;


/**

* Created by onion on 2017-03-30 16:48.

*/

public class JdbcUtils extends JdbcTemplate {


}

在HibernateConfiguration中添加代码:

@Bean

public JdbcUtils jdbcUtils(DataSource dataSource){

  JdbcUtils jdbcUtils = new JdbcUtils();

  jdbcUtils.setDataSource(dataSource);

  return jdbcUtils;

}

在UserService中添加代码:

@Autowired

private JdbcUtils jdbcUtils;


public void test() {

  jdbcUtils.update("INSERT INTO User(name,age) VALUES (?,?)","onion",2);

}


在UserController中添加代码:

@ResponseBody

@RequestMapping("/test")

public String test() {

  userService.test();

  return "success";

}

启动服务,访问:http://localhost:8080/test可以在数据库看到我们刚刚添加的数据。

删除User表的所有数据。

把UserService中的test方法修改为:

public void test() {

  User user1 = new User();

  user1.setName("测试数据");

  user1.setAge(2);

  userDao.save(user1);

  int i = 10/0;

  jdbcUtils.update("INSERT INTO User(name,age) VALUES (?,?)","onion",2);

}

重新部署访问:http://localhost:8080/test可以看到数据库里面没有出现异常前的数据说明我们在使用相同dataSource的时候会在service层用是同一个链接,所以能够进行事物处理。


到此hibernate以及sql执行的相关配置我们就完成了。


添加统一异常处理:

实现程序运行出错时候能够给前端返回指定的错误信息及格式等等。

在utils包中新建BussinessException类,如下:

代码:

package com.utils;


/**

* Created by onion on 2017-03-30 17:26.

*/

public class BussinessException extends RuntimeException{


  public BussinessException(String msg){

      super(msg);

  }

}




在utils包中新建ExceptionResolver类,如下:

代码:

package com.utils;


import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.servlet.HandlerExceptionResolver;

import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.PrintWriter;

import java.util.HashMap;

import java.util.Map;


/**

* Created by onion on 2017-03-30 17:24.

*/

@ControllerAdvice

public class ExceptionResolver implements HandlerExceptionResolver {


  private static ObjectMapper jsonMapper = new ObjectMapper();


  @Override

  public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception exception) {

      //因为不同的插件请求方式不一样,无法绝对保证该请求是否是ajax请求因此不判断,都统一成ajax请求。

      // 判断是否ajax请求

      if (!(request.getHeader("accept").indexOf("application/json") > -1 || (request

              .getHeader("X-Requested-With") != null && request.getHeader(

              "X-Requested-With").indexOf("XMLHttpRequest") > -1))) {

          try {

              request.setCharacterEncoding("UTF-8");

              response.setCharacterEncoding("UTF-8");

              // 如果不是ajax,JSP格式返回

              //为安全起见,只有业务异常我们对前端可见,否则统一归为系统异常

              Map<String, Object> map = new HashMap<String, Object>();

              PrintWriter writer = response.getWriter();

              map.put("success", false);

              map.put("url", request.getRequestURI());

              if (exception instanceof BussinessException) {

                  map.put("errorMsg", exception.getMessage());

              } else {

                  map.put("errorMsg", "系统异常");

              }

              //这里需要手动将异常打印出来,由于没有配置log,实际生产环境应该打印到log里面

              exception.printStackTrace();

              writer.write("<!DOCTYPE html>" +

                      "<html>" +

                      "<head lang=\"en\">" +

                      "<meta charset=\"UTF-8\" />" +

                      "<title>统一异常处理</title>" +

                      "</head>" +

                      "<body>" +

                      "<center><h3>错误路径:" + request.getRequestURL() + "</h3></center>" +

                      "<center><h3>错误信息:" + map.get("errorMsg") + "</h3></center>" +

                      "</body>" +

                      "</html>");

              writer.flush();

              writer.close();

          } catch (Exception e) {

              e.printStackTrace();

          }

      } else {

          // 如果是ajax请求,JSON格式返回

          try {

              request.setCharacterEncoding("UTF-8");

              response.setCharacterEncoding("UTF-8");

              PrintWriter writer = response.getWriter();

              Map<String, Object> map = new HashMap<String, Object>();

              map.put("success", false);

              exception.printStackTrace();

              // 为安全起见,只有业务异常我们对前端可见,否则统一归为系统异常

              if (exception instanceof BussinessException) {

                  map.put("errorMsg", exception.getMessage());

              } else {

                  map.put("errorMsg", "系统异常!");

              }

              writer.write(jsonMapper.writeValueAsString(map));

              writer.flush();

              writer.close();

          } catch (Exception e) {

              e.printStackTrace();

          }

      }

      return null;

  }

}


上面的异常类是用来达到如果是我们自定义的异常(业务异常)就输出我们自定义的异常信息反之都归为系统异常。

启动服务访问:http://localhost:8080/test可以看到我们的设置已经起效。


添加AOP完成日志记录:

在utils包下创建LogAdvice类,如下:

代码:

package com.utils;


import com.fasterxml.jackson.databind.ObjectMapper;

import org.apache.log4j.Logger;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;


/**

* Created by onion on 2017-03-30 21:13.

*/

@Aspect

@Component

public class LogAdvice {


  private final static ObjectMapper jsonMapper = new ObjectMapper();


  private static final Logger logger = Logger.getLogger(LogAdvice.class

          .getName());


  @Pointcut("execution(* com.tgb.service.*.*(..))")

  public void show() {

  }



  @Before("show()")

  public void Befor(JoinPoint jp) {

      try {

          logger.info("调用方法前[" + jp.toLongString() + "] 传入相关数据:" + jsonMapper.writeValueAsString(jp.getArgs()));

      } catch (Exception e) {

          e.printStackTrace();

      }

  }


  @AfterThrowing(value = "show()", throwing = "e1")

  public void afterThrowing(JoinPoint jp, Exception e1) {

      try {

          logger.error("(错误)调用方法后[" + jp.toLongString() + "] 错误信息:" + e1.getMessage());

      } catch (Exception e) {

          e.printStackTrace();

      }

  }


  @AfterReturning(value = "show()", returning = "obj")

  public Object afterReturning(JoinPoint jp, Object obj) {

      try {

          logger.info("调用方法后[" + jp.toLongString() + "] 返回相关数据:" + jsonMapper.writeValueAsString(obj));

      } catch (Exception e) {

          e.printStackTrace();

          logger.error("LogAfter:" + e.getMessage());

      }

      return null;

  }

}

分别为执行前,执行错误后和执行成功后打出日志。


接下来配置日志输出到文件,在application.properties中添加:

logging.file=E://logs/log.log

因为spring boot里面包含log4j所以在设置输出目录后就可以看到我们的日志文件。


到此spring boot的基础搭建基本完成。



代码下载:http://download.csdn.net/detail/qq_36224522/9799483

文档下载:http://download.csdn.net/detail/qq_36224522/9799487



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值