Spring 学习笔记02

时间:2021-01-24 02:51:06

用spring实现一个论坛基本功能

1 运行环境

Linux:Ubun 14.04 64bit

IDE:IntelliJ IDEA 14.03

JDK:1.7.40

MySQL:5.5.44

Tomcat:7.0.47

Maven:3.0.5

2 具体步骤

新建一个Webapp工程,名字就叫spring-bbs-demo 项目的目录结构如下:

├── pom.xml
├── README.MD
├── spring-bbs-demo.iml
└── src
└── main
├── resources
└── webapp
├── index.jsp
└── WEB-INF
└── web.xml

在mysql里创建两张表,数据库名为sampledb

DROP DATABASE IF EXISTS sampledb;
CREATE DATABASE sampledb DEFAULT CHARACTER SET utf8mb4;
USE sampledb; -- 创建用户表
CREATE TABLE t_user (
user_id INT AUTO_INCREMENT NOT NULL COMMENT '用户id',
user_name VARCHAR(30) NOT NULL DEFAULT '' COMMENT '用户名',
credits INT NOT NULL DEFAULT 0 COMMENT '论坛积分',
password VARCHAR(32) NOT NULL DEFAULT ''COMMENT '用户密码',
last_visit TIMESTAMP NOT NULL DEFAULT 0 COMMENT '最后访问时间',
last_ip VARCHAR(23) NOT NULL DEFAULT '0.0.0.0' COMMENT '最后访问ip',
PRIMARY KEY (user_id)
)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT '用户表'; -- 创建用户登陆日志表
CREATE TABLE t_login_log (
login_log_id INT AUTO_INCREMENT NOT NULL COMMENT '日志id',
user_id INT NOT NULL DEFAULT 0 COMMENT '用户id',
ip VARCHAR(23) NOT NULL DEFAULT '0.0.0.0' COMMENT '访问ip',
login_datetime TIMESTAMP NOT NULL DEFAULT 0 COMMENT '访问时间',
PRIMARY KEY (login_log_id)
)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT '用户登陆日志表'; INSERT INTO t_user (user_name,password) VALUES ('admin','123456');

最终项目目录结构

├── pom.xml
├── README.MD
├── spring-bbs-demo.iml
└── src
└── main
├── java
│ └── com
│ └── springbbs
│ ├── dao
│ ├── domain
│ └── service
├── resources
│ └── sql
│ └── user_table_init.sql
└── webapp
├── index.jsp
└── WEB-INF
└── web.xml

NOTE:java为代码根目录,如果不是,可以在java文件夹上右击->Mark Directory As->Resources Root
同理,resources为资源根目录,webappweb根目录,test目录下的java文件夹为TestR Resources Root目录

文件及文件夹相关函数

文件 解释
applicationContext.xml Spring容器配置文件
domain 领域对象(实体类)存放文件夹,往往拥有对应的数据库表,一般要实现Serializable接口,以便序列化
dao 访问实体类的接口,一般一个实体类都会有一个dao与之对应,里面有一些对应的方法
jdbcTemplate Spring对jdbc的简单封装,可以轻松完成大部分的数据库操作而不必频繁的重复对数据库的打开,获取连接,查询,关闭等操作
jdbcTemplate#query() query(String sql,Object[] args,RowCallbackHandler rch).第一个参数不解释了;第二个是占位符(?)对应的参数数据;第三个是查询结果的处理回调接口,该回调接口有一个方法processRow(ResultSet resultSet)负责将查询结果从ResultSet装载到类似于实例类对象的实例中。一般都是使用匿名内部类的方式来调用RowCallbackHandler接口

NOTE:在DAO文件中写的sql语句比较长,多行衔接要注意空格,不然会连在一起,具体小技巧是每一行最后加个空格。

Spring中配置

以上两个DAO实现类中并没有打开/和释放Connection,到底如何访问数据库呢?答案是jdbcspring封装起来了,JdbcTemplate需要一个dataSource,从数据源中获取或返回连接。所以在UserDaoLoginLogDao中都提供了一个带@Autowired注解的jdbcTemplate对象。 所以我们需要先申明一个数据源,然后再定义一个JdbcTemplate Bean,通过Spring的容器上下文自动绑定机制进行Bean的注入。配置文件在Resources文件夹下,名字叫applicationContext.xml,内容如下:

<?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:p="http://www.springframework.org/schema/p"
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"> <!-- 1 加载配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>
<!--2 扫描类包,将标注Spring注解的类自动转化成Bean,同时完成Bean的注入-->
<context:component-scan base-package="com.springbbs.dao"/> <!--3 定义一个使用DBCP实现的数据源-->
<!--如果加载不了配置文件,此处手动改为对应的值-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driver}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/> <!--4 定义jdbc模板Bean-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"/>
</beans>

配置说明

jdbc.properties文件为mysql配置文件,内容如下:

jdbc.driver=com.mysql.jdbc.Driver j
dbc.url=jdbc:mysql://localhost:3306/sampledb
jdbc.username=yourName
jdbc.password=yourPassword

在配置文件中加载mysql配置文件,在定义数据源时需要使用到配置文件中的信息

业务层

在这个登陆实例中,仅有一个业务类,即UserService,它负责将持久层的UserDaoLoginDao组织起来完成用户/密码认证、登陆日志记录等操作。loginSucess将两个DAO组织起来共同完成一个事务性工作:更新两个表,虽然没有事务操作的影子,但是通过Spring事务配置即可。 关于几个注解的解释:

注解 作用
@Service UserService标注为一个服务层的Bean
@Autowired 注入userDaologinLogDao这两个DAO层的Bean

在Spring中装配Service

我们必须告诉Spring哪些业务类需要工作于事务环境下及事务的规则等内容,以便Spring根据这些信息自动为目标业务类添加事务管理功能。对applicationContext.xml更改:

<?xml version="1.0" encoding="UTF-8"?>
<!--1 引入aop及tx命名空间所对应的Schema文件-->
<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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 加载配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/> <!--扫描类包,将标注Spring注解的类自动转化成Bean,同时完成Bean的注入-->
<context:component-scan base-package="com.springbbs.dao"/> <!--扫描service类包,应用Spring的注解配置-->
<context:component-scan base-package="com.springbbs.service"/> <!--配置事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/> <!--通过AOP配置提供事务增强,让service包下所有的Bean的所有方法拥有事务-->
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceMethod" expression="execution(* com.springbbs.service..*(..))"/>
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/>
</aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--定义一个使用DBCP实现的数据源-->
<!--如果加载不了配置文件,此处手动改为对应的值-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driver}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/> <!--定义jdbc模板Bean-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"/>
</beans>

NOTE: 配置文件解释

命名空间

<!--添加`aop`和`tx`命名空间,这样就可以在`xml`配置文件中使用这两个空间下的标签了-->
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"

Service注解扫描目录

<context:component-scan base-package="com.springbbs.service"/>

事务管理器

<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>

aop事务增强

关于aop(面向切片的编程后面会细讲,目前可以理解为拦截和代理即可),execution(* com.springbbs.service.. *(..))的意思就是任意返回值的service包及子包下的任何参数的任何方法都切入进行事务管理。 ```xml

单元测试

jar包依赖

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>

创建单元测试的方法:光标放在在需要测试的类名字上(本例中是UserService),按住Ctrl+Shift+TJunit4单元测试,勾选3个方法即可。 测试类UserServiceTest代码如下:

package com.springbbs.service;

import com.springbbs.domain.User;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.Date; @RunWith(SpringJUnit4ClassRunner.class) // 基于JUnit4的Spring测试框架
@ContextConfiguration(locations = {"classpath:applicationContext.xml"}) //启动Spring容器
public class UserServiceTest { @Autowired
private UserService userService; @Test
public void testHasMatchUser() throws Exception {
boolean b1 = userService.hasMatchUser("admin", "123456");
boolean b2 = userService.hasMatchUser("admin", "1111"); Assert.assertEquals(true, b1);
Assert.assertEquals(false, b2);
} @Test
public void testFindUserByUserName() throws Exception {
User user = userService.findUserByUserName("admin");
Assert.assertEquals("admin", user.getUserName());
} @Test
public void testLoginSucess() throws Exception {
User user = userService.findUserByUserName("admin");
user.setLastIp("127.0.0.1");
user.setLastVistit(new Date());
userService.loginSucess(user);
}
}

NOTE:Spring测试框架可以和Junit4整合,通过Junit4@RunWith注解指定SpringJUnit4ClassRunner.class的测试运行器,该运行器是Spring提供的,可以将Spring容器和Junit4测试框架整合。@ContextConfiguration也是Spring提供的注解,它用于制定Spring的配置文件。 这里需要注意的是,因为我的resources文件夹被指定为资源根目录,所以使用的 classpath路径来加载,即最终在类的根目录下。 在UserServiceTest上右键->Run UserServiceTest即可运行单元测试。最后取数据库中查询登陆日志可以发现成功插入一条记录。

项目代码地址:https://github.com/sjq597/JavaPracticeCode/tree/Spring 分支

tag:https://github.com/sjq597/JavaPracticeCode/tree/spring-bbs-v1.0