之前对JavaWeb的学习不深,打算写一个简单的博客系统来复习一下学过的知识。
项目框架搭建:
项目基于Maven构建,IDE使用的是IDEA。
使用的框架:
- SpringMVC
- Spring
- Hibernate
持久层框架使用的是Hibernate,为什么不用流行的Mybatis,很简单,因为
我 不 会!(很快就要学,希望简单一点……)
不多BB,先给出pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.ethan</groupId>
<artifactId>personal_blog</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 将配置包的版本信息都统一放入此处,方便管理-->
<properties>
<springVersion>4.3.13.RELEASE</springVersion>
<hibernateVersion>5.2.10.Final</hibernateVersion>
<jstlVersion>1.2</jstlVersion>
<!--<taglibVersion>1.1.2</taglibVersion>-->
<servletVersion>4.0.0</servletVersion>
<jspVersion>2.2</jspVersion>
<mysqlVersion>5.1.38</mysqlVersion>
<c3p0Version>0.9.1.2</c3p0Version>
<jsonVersion>1.9.13</jsonVersion>
<jacksonVersion>2.5.0</jacksonVersion>
<log4jVersion>1.2.17</log4jVersion>
<fileuploadVersion>1.3.1</fileuploadVersion>
<lombokVersion>1.16.10</lombokVersion>
</properties>
<dependencies>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!--spring四个核心jar包 + spring-orm-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${springVersion}</version>
</dependency>
<!--spring-web + spring-webmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springVersion}</version>
</dependency>
<!--hibernate-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernateVersion}</version>
</dependency>
<!-- hibernate 缓存, 视情况添加-->
<!--<dependency>-->
<!--<groupId>org.hibernate</groupId>-->
<!--<artifactId>hibernate-ehcache</artifactId>-->
<!--<version>${hibernateVersion}</version>-->
<!--</dependency>-->
<!--servlet + jsp-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servletVersion}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jspVersion}</version>
<scope>provided</scope>
</dependency>
<!--JSTL-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstlVersion}</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysqlVersion}</version>
</dependency>
<!-- c3p0数据库连接池-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0Version}</version>
</dependency>
<!-- json数据 使springMVC可以返回json值 ,视情况添加-->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${jsonVersion}</version>
</dependency>
<!-- Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jacksonVersion}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jacksonVersion}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jacksonVersion}</version>
</dependency>
<!-- log4j配置, 视情况添加-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4jVersion}</version>
</dependency>
<!--文件 上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${fileuploadVersion}</version>
</dependency>
<!-- lombok插件导包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombokVersion}</version>
</dependency>
</dependencies>
</project>
然后是配置文件:
- DataBaseConfig.properties(里面是常用的一些数据库配置,用于在Spring的配置文件中引用)
#database connection config
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://127.0.0.1:3306/数据库名?useUnicode=true&characterEncoding=utf-8
jdbc.username = 用户名
jdbc.password = 密码
#hibernate config
hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.show_sql = true
hibernate.format_sql = true
hibernate.hbm2ddl.auto = update
hibernate.connection.autocommit = true
- applicationContext.xml(Spring的配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--********************************************配置Spring***************************************-->
<!--自动扫描-->
<context:component-scan base-package="me.ethan">
<!--扫描时跳过 @Controller 注解的JAVA类(控制器)-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--********************************************配置hibernate********************************************-->
<!--扫描配置文件(这里指向的是之前配置的那个DataBaseConfig.properties)-->
<context:property-placeholder location="classpath:hibernate/DataBaseConfig.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}"/> <!--数据库连接驱动-->
<property name="jdbcUrl" value="${jdbc.url}"/> <!--数据库地址-->
<property name="user" value="${jdbc.username}"/> <!--用户名-->
<property name="password" value="${jdbc.password}"/> <!--密码-->
<property name="maxPoolSize" value="40"/> <!--最大连接数-->
<property name="minPoolSize" value="1"/> <!--最小连接数-->
<property name="initialPoolSize" value="10"/> <!--初始化连接池内的数据库连接-->
<property name="maxIdleTime" value="20"/> <!--最大空闲时间-->
</bean>
<!--配置session工厂,注意hibernate的版本-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="me.ethan.entity"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> <!--hibernate根据实体自动生成数据库表-->
<prop key="hibernate.dialect">${hibernate.dialect}</prop> <!--指定数据库方言-->
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <!--在控制台显示执行的数据库操作语句-->
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop> <!--在控制台显示执行的数据哭操作语句(格式)-->
<prop key="hibernate.current_session_context_class">
org.springframework.orm.hibernate5.SpringSessionContext
</prop>
<prop key="hibernate.connection.autocommit">${hibernate.connection.autocommit}</prop> <!--自动提交,配合getCurrentSession一起使用-->
</props>
</property>
</bean>
<!-- 事物管理器配置,注意hibernate的版本 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!--启用事务注解-->
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
</beans>
- dispatcher-servlet.xml(SpringMVC的配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 启动注解驱动的spring MVC功能,注册请求url和注解POJO类方法的映射-->
<mvc:annotation-driven/>
<!--配置注解扫描的包-->
<context:component-scan base-package="me.ethan.controller"/>
<!--配置视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--静态资源映射-->
<mvc:resources mapping="/js/**" location="/resources/js/" />
<mvc:resources mapping="/css/**" location="/resources/css/" />
<mvc:resources mapping="/img/**" location="/resources/img/" />
</beans>
- web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<welcome-file-list>
<welcome-file>/index.jsp</welcome-file>
</welcome-file-list>
<!--加载spring配置文件到上下文中-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<!--配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置字符集过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置DispatcherServlet-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/dispatcher-servlet.xml</param-value>
</init-param>
<!--配置容器在启动的时候就加载这个servlet并实例化-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 补充:项目目录及结构
遇到的问题及解决方案:
搭建SSH框架的过程中,遇到了不少棘手的问题。写这篇博文的初衷就是为了记录开发中的问题,与大家一起分享。一些拙见,抛砖引玉:
- IDEA中在web.xml中配置了ContextLoaderListener报异常:ClassNotFound
分析原因:与maven的依赖导入有关……
解决方法一:打开project structure,在Aritifacts下,右边的依赖目录的上方,右击项目名称,选择Put Into Output Root
解决方法二:自行在左边的WEB-INF应用目录下,新建一个Directory,名为lib,在右边 右击所有 有关spring的jar包(包括spring mvc的有关依赖),选择put into WEB-INF/lib
- 运行报错 : org.hibernate.MappingException: Could not get constructor for
org.hibernate.persister.entity.SingleTableEntityPersister
分析原因:
1.实体类的属性对象没有设置setter或者getter,或者是设置setter或者getter时没有按照Hibernate规范。
2.没有导入javassist的jar文件。(加入lib目录下才可以)
3.实体类中的属性对象名和映射文件的property name不一致。
- 启动项目的时候一直出现如下的提示:Causedby:org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type
[com.chainmobile.test.service.LoginService] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations:即注入类型未找到的异常
分析原因:把service注解到interface上面了
解决方法:需要把这个放到service的实现类上。
- Error executing DDL via JDBC Statement导致的建表失败
分析原因:
1.数据库方言配置错误,如我的配置原来是 hibernate.dialect = org.hibernate.dialect.MySQLInnoDBDialect 修改为 hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect 即可。
2.依赖导入错误,需要引入相关的依赖
这里提一句:MySQL5.5以后默认使用InnoDB存储引擎,其中InnoDB和BDB提供事务安全表,其它存储引擎都是非事务安全表。
- Could not obtain transaction-synchronized Session for current thread
提示无法获取当前线程的事务同步session
分析原因:
getCurrentSession方法与事务有关,分析一下getCurrentSession和openSession的区别:
1.openSession每次打开都是新的Session,所以多次获取的Session实例是不同的,并且需要人为的调用close方法进行Session关闭
2.getCurrentSession是从当前上下文中获取Session并且会绑定到当前线程,第一次调用时会创建一个Session实例,如果该Session未关闭,后续多次获取的是同一个Session实例;事务提交或者回滚时会自动关闭Sesison,无需人工关闭
解决方法:可以使用openSession获取session实例;最好的方法是使用事务管理,仍然使用getCurrentSession
- spring的schema约束的添加
需要注意:在添加schema约束时除了添加约束头部,还要添加相应的两个约束文件所在URL。
Spring推荐我们使用不带版本号的schema
- Hibernate注解开发:如何生成UUID的主键策略?
//配置uuid,本来jpa是不支持uuid的,但借用hibernate的方法可以实现。
@GenericGenerator(name = "uuid", strategy = "uuid")
@GeneratedValue(generator = "uuid")
- Spring @Transactional事务配置无效原因
分析原因:
1.如使用mysql且引擎是MyISAM,则事务会不起作用,原因是MyISAM不支持事务,可以改成InnoDB
2.如果使用了spring+springmvc,则context:component-scan重复扫描问题可能会引起事务失败。(也是本次配置事务管理却失效的原因)
3.@Transactional 注解开启配置,必须放到listener里加载,如果放到DispatcherServlet的配置里,事务也是不起作用的。
4.@Transactional 注解只能应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错,事务也会失效。
5. Spring团队建议在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。在接口上使用 @Transactional注解,只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。
解决方法:修改配置文件,applicationContext.xml中扫描过的包,在dispatcher-servlet.xml中不能重复扫描。
enmmm……开发暂时遇到了一些难题,由于自己前端学的不好,尝试了layui和easyui两个框架后都失败了,因此决定先把JavaScript和JQuery好好看看,打好基础,前端页面开发完成再写逻辑吧。