Spring 学习笔记02
用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
为资源根目录,webapp
为web
根目录,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
,到底如何访问数据库呢?答案是jdbc
被spring
封装起来了,JdbcTemplate
需要一个dataSource
,从数据源中获取或返回连接。所以在UserDao
和LoginLogDao
中都提供了一个带@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
,它负责将持久层的UserDao
和LoginDao
组织起来完成用户/密码认证、登陆日志记录等操作。loginSucess
将两个DAO
组织起来共同完成一个事务性工作:更新两个表,虽然没有事务操作的影子,但是通过Spring
事务配置即可。 关于几个注解的解释:
注解 | 作用 |
---|---|
@Service | 将UserService 标注为一个服务层的Bean |
@Autowired | 注入userDao 和loginLogDao 这两个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+T
,Junit4
单元测试,勾选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
Spring 学习笔记02的更多相关文章
- Spring学习笔记——02 Bean的命名及实例化
一.Bean的命名 前一篇讲到IoC是一个管理Bean的容器,Bean多数情况下都是通过XML文件进行配置的,其中Bean的命名有以下几种方式,现在梳理一下. 1. 不指定id,只配置类名 <b ...
- Redis:学习笔记-02
Redis:学习笔记-02 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 4. 事物 Redis 事务本 ...
- 软件测试之loadrunner学习笔记-02集合点
loadrunner学习笔记-02集合点 集合点函数可以帮助我们生成有效可控的并发操作.虽然在Controller中多用户负载的Vuser是一起开始运行脚本的,但是由于计算机的串行处理机制,脚本的运行 ...
- 【Spring学习笔记-MVC-3.1】SpringMVC返回Json数据-方式1-扩展
<Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...
- spring学习笔记(一) Spring概述
博主Spring学习笔记整理大部分内容来自Spring实战(第四版)这本书. 强烈建议新手购入或者需要电子书的留言. 在学习Spring之前,我们要了解这么几个问题:什么是Spring?Spring ...
- Java框架spring 学习笔记(十八):事务管理(xml配置文件管理)
在Java框架spring 学习笔记(十八):事务操作中,有一个问题: package cn.service; import cn.dao.OrderDao; public class OrderSe ...
- Spring学习笔记2——表单数据验证、文件上传
在上一章节Spring学习笔记1——IOC: 尽量使用注解以及java代码中,已经搭建了项目的整体框架,介绍了IOC以及mybatis.第二节主要介绍SpringMVC中的表单数据验证以及文件上传. ...
- 机器学习实战(Machine Learning in Action)学习笔记————02.k-邻近算法(KNN)
机器学习实战(Machine Learning in Action)学习笔记————02.k-邻近算法(KNN) 关键字:邻近算法(kNN: k Nearest Neighbors).python.源 ...
- OpenCV 学习笔记 02 使用opencv处理图像
1 不同色彩空间的转换 opencv 中有数百种关于不同色彩空间的转换方法,但常用的有三种色彩空间:灰度.BRG.HSV(Hue-Saturation-Value) 灰度 - 灰度色彩空间是通过去除彩 ...
随机推荐
- PHP自动添加http://头 转换网址为链接
有时候,当我们需要用户输入网址的时候,一般我们会让用户省略掉"http://",当提交完成后用代码自动再加上http://,若有需要,我们 还可将网址转换成链接的形式,类似于众多网 ...
- EDIT编辑框
编辑框 编辑框的主要作用是让用户输入文本,例如要求用户在编辑框中输入密码的文本. .基础知识 编辑框里的文本可以是单行,也可以是多行,后者的风格取值为 ES_MULTILINE.一般对于多行文本编辑框 ...
- Unity3D 经验记录
1.using UnityEngine.SceneManagement; 当在01场景调用02场景时,再载入回01场景时,代码保存的变量不会初始化,预制物体脚本内的变量会初始化. 2.当子物体太多时, ...
- 剑指offer之O(1)算法删除指针所指向的节点
题目如图: 1.把要删除pToBeDeleted的节点的后面节点覆盖点要删除的节点pToBeDeleted 2.要考虑如果删除的节点是最后一个节点怎么办 3.要考虑如果总共只有一个节点,删除的是头结点 ...
- Moving Acerage
http://zh.wikipedia.org/zh/%E7%A7%BB%E5%8B%95%E5%B9%B3%E5%9D%87
- Android 给TextView添加点击事件
首先设定TextView的clickable属性为true. 可以在布局文件中进行设定,比如: <TextView android:id="@+id/phone" andro ...
- 【HDOJ】2585 Hotel
字符串水题. #include <cstdio> #include <cstring> #include <cstdlib> #define MAXN 55 cha ...
- 数据加密算法---base64
简介 base64是把8位字符打散,转换成不被人直接识别的形式,严格来说它并不是加密算法,只能算做一种编码方式 原理 首先准备64个字符数组做为“数组库” ['A', 'B', 'C', ... 'a ...
- squid 代理服务器安装配置
ubuntu16.04 安装squid代理服务器配置 本文参考 http://www.cnblogs.com/newflypig/archive/2012/09/28/2862000.html 1,删 ...
- React Native 初识
Facebook 在 React.js Conf 2015 大会上推出了基于 JavaScript 的开源框架 React Native,本中文教程翻译自 React Native 官方文档. Rea ...