个人博客系统之框架搭建

1、写在前面

本篇博客是个人博客系统系列第二篇,以下是其他博客的链接:

2、新建项目

2.1 创建SpringBoot项目

首先新建一个SpringBoot项目,项目信息大家可以随便填,不过为了开发方便,最好跟我的截图保持一致:
新建项目

2.2 添加依赖

点击下一步后选择依赖,其中:

  • 必选依赖:
    • Thymeleaf
    • Spring Security
    • MyBatis Framework
    • MySQL Driver
    • Lombok【这个依赖其实也非必选,不过加了可以少写很多代码】
  • 非必选依赖:
    • Spring Boot DevTools【这个依赖用于热部署,可以不重启服务器部署项目,不过我没咋用,可以不加】

添加依赖
一直点击下一步,直到项目创建完成,打开pom.xml文件,这里边有个线程池依赖(可以不加,我貌似没在项目上用到,不过后期优化可能会用到)在上边的截图中找不到,因此需要手动添加下:

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.10</version>
</dependency>

2.3 创建多环境配置

在resources文件夹下创建一下四个文件:

  • application.properties
  • application-dev.properties
  • application-test.properties
  • application-prod.properties

当然我们这个项目用不到这么多配置,嫌麻烦的朋友也可以只创建第一个文件,我这边只是想尽量靠近企业开发。
其中application.properties文件内容如下:

spring.profiles.active=dev

表示启用开发环境的配置,开发环境配置在application-dev.properties文件中,内容如下:

# tomcat端口号
server.port=8080

# 线程池类型,前面线程池依赖没加的朋友,可以把这行代码去掉
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 数据库配置,自行替换
spring.datasource.url=jdbc:mysql://192.168.203.128:3306/personal_blog?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456

# 视图解析
spring.mvc.view.suffix=.html

# mapper.xml文件位置
mybatis.mapper-locations=classpath:mapper/*.xml
# 在控制台打印SQL语句
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# 日志级别
logging.level.root=info
# 因为是开发环境的配置,所以配置为debug,在开发测试环境中,可以相应的提高日志级别
logging.level.com.alageek.personalblog=debug

开发阶段,测试和生产的配置暂且不写,有兴趣的朋友可以复制开发的配置,修改下端口号试试。

3、异常处理

项目运行过程中肯定会有各种各样的异常抛出,我们期望将这些异常全部捕获,进行统一处理,并且在某些情况下,我们也期望抛出来的异常是我们自定义的异常,比如这里我们自定义一个博客未找到的异常:

/**
 * 博客未找到异常
 * @author AlaGeek
 */
@ResponseStatus(HttpStatus.NOT_FOUND)
public class BlogNotFoundException extends RuntimeException {

    private static final long serialVersionUID = 3780352823465733637L;

    public BlogNotFoundException() {
    }

    public BlogNotFoundException(String message) {
        super(message);
    }

    public BlogNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

当我们访问系统中不存在的博客时,将会返回一个404的http错误到前端,这里我们让其抛出博客未找到异常,从而能被我们的全局异常处理捕获,以便跳转到相应页面并做相应处理。
这边博客未找到异常只是做个演示,让大家明白下怎么自定义异常,在全局异常处理中我们还是先将所有异常都捕获,其代码如下:

/**
 * 全局异常处理机制
 * @author AlaGeek
 */
@Slf4j
@ControllerAdvice
public class ControllerExceptionHandler {

    /**
     * 异常处理
     * @param e       异常对象
     * @param request 请求对象
     * @return 返回错误页面
     */
    @ExceptionHandler(value = Exception.class)
    public ModelAndView resolveException(Exception e, HttpServletRequest request) throws Exception {
        log.debug("Request URL: {}, Exception: {}", request.getRequestURL(), e);
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }
        String viewName = "error/error";
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject(BlogConstant.ATTR_NAME_URL, request.getRequestURL());
        modelAndView.addObject(BlogConstant.ATTR_NAME_EXCEPTION, e);
        modelAndView.setViewName(viewName);
        return modelAndView;
    }

}

之前在尚筹网项目中有用到这个异常处理机制,如果不懂这个可以看看我的这篇博客:admin-component异常处理机制
上方代码表示异常被捕获后,将会跳转到error目录下的error.html页面【.html是前面配置的视图解析】,因此需要在resources/template目录下新建error文件夹,并在该文件夹下创建error.html文件,error.html页面长什么样无关紧要,不过需要在其中插入以下代码:

<!--/*/
<div th:utext="'&lt;!--'" th:remove="tag"></div>
<div th:utext="'Failed Request URL:' + ${url}" th:remove="tag"></div>
<div th:utext="'Exception Message:' + ${exception.message}" th:remove="tag"></div>
<ul th:remove="tag">
    <li th:each="st: ${exception.stackTrace}" th:remove="tag"><span th:utext="${st}" th:remove="tag"></span></li>
</ul>
<div th:utext="'--&gt;'" th:remove="tag"></div>
/*/-->

代码运用了thymeleaf模板,用于获取异常的具体信息,并且将这段异常信息放在页面的源码注释中,而不是展示在前端页面供用户查看,这样做的目的主要也是为了调试方便,开发的时候可以随时看控制台信息,不过测试环境或者生产环境,如果直接看源码就能看到异常信息的话,想必是非常方便的。

4、日志处理

有了异常处理,还想做的就是每次用户访问我这个博客系统的时候,就把这次访问的相关信息记下来,打印出日志。
对于访问日志,我希望能够记录以下信息:

  • 请求url
  • 请求ip
  • 请求方法
  • 请求参数
  • 返回内容

我们不可能在每个controller的函数里都加上记录日志的代码,那样太麻烦了,因此需要用到spring框架的绝技——AOP,也就是面向切面编程。
首先引入AOP相关的依赖,在pom.xml中添加如下代码:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

然后新增一个日志记录类LogAspect,代码如下:

@Slf4j
@Aspect
@Component
public class LogAspect {

    @Pointcut("execution(* com.alageek.personalblog.web.*.*(..))")
    public void log() {

    }

    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            String url = request.getRequestURL().toString();
            String ip = request.getRemoteAddr();
            String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            RequestLog requestLog = new RequestLog(url, ip, classMethod, args);
            log.info("Request: {}", requestLog);
        }
    }

    @AfterReturning(returning = "result", pointcut = "log()")
    public void doAfterReturn(Object result) {
        log.info("Result: {}", result);
    }

    @Data
    @AllArgsConstructor
    private static class RequestLog {
        private String url;
        private String ip;
        private String classMethod;
        private Object[] args;
    }

}

5、写在后面

这部分为框架搭建,其实新建一个项目没有这么麻烦,idea鼠标点几下的事情,只是为了后续开发和调试方便,所以要做些相关配置,比如日志处理,比如异常处理。

crm项目的架构 * 创建web工程 * 引入jar包 * mysql的驱动包 * hibernate需要的jar包 * spring需要的jar包 * struts2需要的jar包 * jstl 需要的jar包 * junit需要的jar包 * 包的介绍 * cn.itcast.crm.container:重新封装spring容器 * cn.itcast.crm.dao:放置的是dao接口 * cn.itcast.crm.dao.impl:放置的是dao接口的实现类 * cn.itcast.crm.domain:放置的是po类、po类和数据库表关联的映射文件 * cn.itcast.crm.service:业务层的接口 * cn.itcast.crm.service.impl:业务层的接口的实现类 * cn.itcast.crm.web.action:struts2的action * cn.itcast.crm.web.form:封装页面数据的javaBean * junit:开发人员测试用的 * 搭建hibernate层 * 定义需求:部门信息的页面数据要插入到数据库中 * 定义表 CREATE TABLE `sys_user_group` ( `id` INTEGER(11) NOT NULL AUTO_INCREMENT, #编号 `remark` TEXT, #备注 `name` VARCHAR(100) DEFAULT NULL, #部门名称 `principal` VARCHAR(50) DEFAULT NULL, #部门负责人 `incumbent` VARCHAR(200) DEFAULT NULL, #部门职能 PRIMARY KEY (`id`) ) * 创建po对象,放置在cn.itcast.crm.domain包下 public class SysUserGroup implements java.io.Serializable { private Integer id; private String remark; // 备注 private String name; // 部门名称 private String principal; // 部门负责人 private String incumbent; // 部门职能 } * 创建表和po之间的映射文件SysUserGroup.hbm.xml 放置在cn.itcast.crm.domain包下 * SysUserGroup.hbm.xml文件的内容直接看该文件即可 * 创建hibernate.cfg.xml文件连接数据库,加载SysUserGroup.hbm.xml文件,放置src下 <session-factory> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/itcast0807crm</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.autocommit">true</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="hibernate.show_sql">true</property> <mapping resource="cn/itcast/crm/domain/SysUserGroup.hbm.xml"/> </session-factory> * 测试.放置在junit包下 public class TestHibernate { @Test public void testHibernateConf(){ Configuration config=new Configuration(); config.configure(); SessionFactory sf=config.buildSessionFactory(); Session s=sf.openSession(); Transaction tx=s.beginTransaction(); SysUserGroup sysUserGroup=new SysUserGroup(); sysUserGroup.setName("销售部"); sysUserGroup.setPrincipal("xxx"); sysUserGroup.setIncumbent("ttt"); s.save(sysUserGroup); tx.commit(); s.close(); } } * 搭建spring和hibernate * 创建beans.xml文件,放置在src下 * 引入命名空间 bean tx context aop <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> * 配置如下: <!-- 1 配置注解的自动扫描--> <context:component-scan base-package="cn.itcast.crm"/> <!--3 配置本地化代理工程bean,这是spring整合hibernate的入口 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation"> <!--表示在类路径下加载hibernate.cfg.xml --> <value>classpath:hibernate.cfg.xml</value> </property> </bean> <!--4 创建事务管理器 aop切面--> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!--5 配置处理事务的注解--> <tx:annotation-driven transaction-manager="txManager"/> * 创建dao层共同的接口,放置在cn.itcast.crm.dao下 public interface ICommonDao<T> { public void save(T entity); } * 创建dao层共同的接口的实现类,,放置在cn.itcast.crm.dao.impl下 public class CommonDaoImpl<T> extends HibernateDaoSupport implements ICommonDao<T> { public void save(T entity) { this.getHibernateTemplate().save(entity); } @Resource(name="sessionFactory") //注入sessionFactory public void setSessionFactoryDI(SessionFactory sessionFactory) { System.out.println("sessionFactory "+sessionFactory); //调用父类的setSessionFactory方法,注入sessionFactory super.setSessionFactory(sessionFactory); } } * 创建部门的dao接口 SysUserGroupDao接口 放在cn.itcast.crm.dao包下 public interface ISysUserGroupDao extends ICommonDao<SysUserGroup> { public final static String SERVICE_NAME="cn.itcast.crm.dao.impl.SysUserGroupDaoImpl"; } * 创建部门的dao接口的实现类 放在cn.itcast.crm.dao.impl包下 @Repository(ISysUserGroupDao.SERVICE_NAME) public class SysUserGroupDaoImpl extends CommonDaoImpl<SysUserGroup> implements ISysUserGroupDao { } * 测试,放置在junit包下 public class TestSysUserGroupDao { @Test public void testSave() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); ISysUserGroupDao sysUserGroupDao = (ISysUserGroupDao) ctx.getBean(ISysUserGroupDao.SERVICE_NAME); SysUserGroup sysUserGroup = new SysUserGroup(); sysUserGroup.setName("销售部"); sysUserGroup.setPrincipal("xxx"); sysUserGroup.setIncumbent("ttt"); sysUserGroupDao.save(sysUserGroup); } } * 创建部门的业务层接口 ,放置在cn.itcast.crm.service包下 public interface ISysUserGroupService { public final static String SERVICE_NAME="cn.itcast.crm.service.impl.SysUserGroupServiceImpl"; public void saveSysUserGroup(SysUserGroup sysUserGroup); } * 创建部门的业务层接口实现类,放置在cn.itcast.crm.service.impl包下 @Transactional(readOnly=true) @Service(ISysUserGroupService.SERVICE_NAME) public class SysUserGroupServiceImpl implements ISysUserGroupService { @Resource(name=ISysUserGroupDao.SERVICE_NAME) private ISysUserGroupDao sysUserGroupDao; @Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,readOnly=false) public void saveSysUserGroup(SysUserGroup sysUserGroup) { sysUserGroupDao.save(sysUserGroup); } } * 测试 public class TestSysUserGroupService { @Test public void testSavex() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); ISysUserGroupService sysUserGroupService = (ISysUserGroupService) ctx.getBean(ISysUserGroupService.SERVICE_NAME); SysUserGroup sysUserGroup = new SysUserGroup(); sysUserGroup.setName("销售部"); sysUserGroup.setPrincipal("xxx"); sysUserGroup.setIncumbent("ttt"); sysUserGroupService.saveSysUserGroup(sysUserGroup); } } * 搭建struts2(保存部门信息) * jsp页面(sys/group/add.jsp) * 请求的路径/sys/sysUserGroupAction_save.do * 根据路径创建SysUserGroupAction和在action中增加save方法,放置在cn.itcast.crm.web.action包下 public class SysUserGroupAction extends ActionSupport public String save() throws IllegalAccessException, InvocationTargetException{ System.out.println("xxxxxxxxxxxxxxxxxxxxxxxx "); return null; } } * 建立请求路径和action之间的关联 * 创建struts.xml文件,放置在src下 * 文件内容如下: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN" "http://struts.apache.org/dtds/struts-2.1.7.dtd"> <struts> <!-- 配置请求后缀名.do --> <constant name="struts.action.extension" value="do"/> <!-- 配置主题为简单主题 --> <constant name="struts.ui.theme" value="simple"/> <!--配置struts2的模式为开发模式--> <constant name="struts.devMode" value="true"/> <package name="sys" namespace="/sys" extends="struts-default"> <action name="sysUserGroupAction_*" class="cn.itcast.crm.web.action.SysUserGroupAction" method="{1}"> <result name="add">/sys/group/add.jsp</result> </action> </package> </struts> * 在web.xml文件配置struts2的过滤器 <filter> <filter-name>StrutsPrepareAndExecuteFilter</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>StrutsPrepareAndExecuteFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> * 测试 * 定义javaBean(vo对象)接收表单数据,放置在cn.itcast.crm.web.form包下 public class SysUserGroupForm implements java.io.Serializable { private String id; private String name; private String principal; private String incumbent; private String remark; } * action要实现模型驱动接口 public class SysUserGroupAction extends ActionSupport implements ModelDriven<SysUserGroupForm>{ private SysUserGroupForm sysUserGroupForm=new SysUserGroupForm(); public String save() throws IllegalAccessException, InvocationTargetException{ System.out.println("xxxxxxxxxxxxxxxxxxxxxxxx "); return null; } public SysUserGroupForm getModel() { return sysUserGroupForm; } } * 测试,SysUserGroupForm是否接收到值 * 如何在struts2的SysUserGroupAction中的save方法中,获取spring容器中bean节点的对象 * 创建ServiceProvinderCore,加载beans.xml文件,放置在cn.itcast.crm.container包下 public class ServiceProvinderCore { protected ApplicationContext ctx; /** * @param filename beans.xml */ public void load(String filename){ ctx=new ClassPathXmlApplicationContext(filename); } } * 创建ServiceProvinder类,获取获取spring容器中bean节点的对象,放置在cn.itcast.crm.container包下 public class ServiceProvinder { private static ServiceProvinderCore sc; static{ System.err.println("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); sc=new ServiceProvinderCore(); sc.load("beans.xml"); } public static Object getService(String beanName){ System.err.println("ppppppppppppppppppppppp"); if(StringUtils.isBlank(beanName)){ throw new RuntimeException("您要访问的服务名称不能为空"); } Object bean=null; //如果spring容器中包含beanName if(sc.ctx.containsBean(beanName)){ bean=sc.ctx.getBean(beanName); } //如果spring容器中不包含beanName if(bean==null){ throw new RuntimeException("您要访问的服务名称["+beanName+"]不存在"); } return bean; } } * 测试 @Test public void testSave() { ISysUserGroupService sysUserGroupService=(ISysUserGroupService)ServiceProvinder.getService(ISysUserGroupService.SERVICE_NAME); SysUserGroup sysUserGroup = new SysUserGroup(); sysUserGroup.setName("销售部"); sysUserGroup.setPrincipal("xxx"); sysUserGroup.setIncumbent("ttt"); sysUserGroupService.saveSysUserGroup(sysUserGroup); } * 在 SysUserGroupAction中的save方法中增加如下代码 public String save() throws IllegalAccessException, InvocationTargetException{ System.out.println("sysUserGroupForm.getName() "+sysUserGroupForm.getName()); //实例化po对象 SysUserGroup sysUserGroup=new SysUserGroup(); //赋值vo对象的值到po中 BeanUtils.copyProperties(sysUserGroup, sysUserGroupForm); //获取业务层的对象(本项目struts2和spring是分离的) ISysUserGroupService sysUserGroupService= (ISysUserGroupService)ServiceProvinder.getService(ISysUserGroupService.SERVICE_NAME); //调用业务层保存po对象 sysUserGroupService.saveSysUserGroup(sysUserGroup); return null; } * 测试:
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值