spring对我来说已经不陌生了,在与同学合作的项目中经常用到,可是对spring一直都没有一个清晰地知识结构,想来想去决定开博客写下自己的学习轨迹。
本人自选教材为《Spring3.X企业应用实战》,在此对其细致的讲解表示衷心感谢!
首先来个Hello World 感受一下Spring为开发带来的变化。
文件结构如下:
架spring项目首先肯定是spring库,在官网上找了半天,各种让去git上下,看源码是方便了,可是release版的jar包该去哪找啊喂!
在CSDN上找了个下载资源:http://download.csdn.net/detail/jiangw1235/5973995
东西很全,可以用。
项目的功能是用户登录,在登录后会有一条日志插入进数据库中。
项目用了注解方式注入bean,所以先配注解扫描器:
在<beans>下:
<context:component-scan base-package="dao"/>
<context:component-scan base-package="service"/>
配数据源:这里用的是纯粹的spring封装jdbc的方式
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
</property>
<property name="url"
value="jdbc:mysql://localhost:3306/test">
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
配一个jdbc模板类:
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource" />
这个作为到层的底层支持。
OK可以写dao了
public class User {
private int id;
private String name;
private String password;
private int departId;
}
public class Log {
private int id;
private int userId;
private String ip;
private Date date;
public int getId() {
return id;
}
}
package dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import po.Log;
@Repository //repository是仓库,储藏室的意思,这里意思应该是“存储层”
public class LogDao {
@Autowired//注解方式注入对象,通过反射绕过java访问域的限制,连set方法都不需要了。
private JdbcTemplate jdbcTemplate;
public void insertLoginLog(Log log){
String sqlStr = "insert into log(userid,ip,date) values(?,?,?)";
Object args[] = new Object[]{log.getUserId(),log.getIp(),log.getDate()};
jdbcTemplate.update(sqlStr,args);
//强大的jdbc模板类,由spring提供,在applicationContext中进行装配,好像没有找到有关分页的操作,
//是自己做template类的重要参考
}
}
package dao;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import po.User;
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public User login(String userName,String pass){
String sql = "select * from user where name = ? and password = ?";
//返回键值对的形式值得学习
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, new Object[]{userName,pass});
if(list.size()==1){
Map<String,Object> map = list.get(0);
User user = new User();
user.setId(((Long) map.get("id")).intValue());
user.setName((String) map.get("name"));
user.setPassword((String) map.get("password"));
user.setDepartId(((Long) map.get("deptid")).intValue());
return user;
}
return null;
}
}
dao写好开始写service:
注释中提到,在这一层用到了自动事务,这个需要在xml中配置。package service; import java.sql.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import po.Log; import po.User; import dao.LogDao; import dao.UserDao; @Service//service层, public class UserService { @Autowired private UserDao userDao; @Autowired private LogDao logDao; //在applicationContext中配置了AOP,使得每个在Service中的方法都有了自动事务。但如下面这句, //只有一句话,他是如何做到总是在最前面开事务,又在最后面管事务的,细节需要在学习 public User login(String userName,String pass){ return userDao.login(userName, pass); } public void doLog(User user){ Log log = new Log(); log.setUserId(user.getId()); log.setDate(new Date(new java.util.Date().getTime())); log.setIp("127.0.0.1"); logDao.insertLoginLog(log); } }
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource" />
<!-- 使用事务管理类使service中所有的方法都添加事务 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true" >
<aop:pointcut expression="execution(* service..*(..))" id="serviceMethod"/>
<!-- 此处即可看作是自动事务+AOP,前面定义了自动事务的对象,在此处的aop设置中引用之 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" />
</aop:config>
这一过程略显复杂,我也只大概知道意图。
书中在这时对service做了单元测试,我也借此熟悉了一下单元测试的过程:
1.导入Junit4.5包,4在spring3.2.4中好像出了问题。
2.建测试文件夹,建包,建一个普通的类,加上Junit注解就可以使用Junit测试了
package test;
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 po.User;
import service.UserService;
//这个类是spring的测试类,spring的应用只需要导入包,然后配置applicationContext就OK了。轻量级就体现在这
//至于在普通java项目中怎么初始化Ioc容器,还要继续学习。
@RunWith(SpringJUnit4ClassRunner.class)//这个注解是junit的,标记这个类可以使用junit执行,但这些东西毕竟是spring框架的,具体的驱动类自然由spring提供
@ContextConfiguration(locations={"/applicationContext.xml"})//这个注解用来指定这个test类运行的上下文,来自springFramework的test包
public class TestUserService {
@Autowired
private UserService userService;
@Test//标记了这个注解的方法会run as junit的时候被执行,否则是不执行的。
public void testLogin(){
User u = userService.login("test", "123456");
userService.doLog(u);
System.out.println(u.getName()+" "+u.getPassword()+" "+u.getDepartId());
}
}
测试通过,下面就要写Web有关的东西了。该项目用了Spring MVC作为视图层,所以在web.xml中配置Spring MVC的有关内容。另外Web容器要负责初始化Spring框架,所以,有关Spring的监听、配置引入等也在其中。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>springTest1</display-name>
<!-- <welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> -->
<context-param>
<!-- 让javaEE载入spring的上下文配置 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<!-- 引入Ioc容器了!负责启动Ioc容器监听器,原来javaEE靠这个来初始化spring-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<!-- spring MVC的载体上场,一个大servlet,主控Servlet,名字就能看出来,专管Dispatch -->
<servlet-name>mainServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- javaEE的配置,吧主控servlet挡在入口,拦截所有的.html请求,.html是个技巧,很好的隐藏了技术又能优化搜索引擎抓取,真想请求静态html的时候可以用.htm来请求 -->
<servlet-mapping>
<servlet-name>mainServlet</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
接下来在WEB-INFO下面建立对mainServlet的配置文件,通过为逻辑名添加前、后缀的方法来规定跳转页面文件与逻辑名称的映射关系,这个文件的文件头与applicationContext.xml相同,也同样在<beans>下书写内容。
<context:component-scan base-package="action"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:viewClass="org.springframework.web.servlet.view.JstlView"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
配置好了Spring MVC,我们可以写控制层代码了,控制层代码在这里居然是个普通类!没继承任何父类,没实现任何接口。用最朴素的方式实现功能!
public class LoginCommand {
private String userName;
private String password;
}
package action;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import po.LoginCommand;
import po.User;
import service.UserService;
@Controller//MVC嘛,这是控制层
public class LoginController {//这个类没继承任何父类,没实现任何接口
@Autowired
private UserService userService;
@RequestMapping(value="/index.html")//方法对应的请求路径
public String loginPage(){//不带参的跳转可以直接返回字符串
return "login";
}
@RequestMapping(value="/login.html")
public ModelAndView loginCheck(HttpServletRequest request,LoginCommand loginCommand){
//带参的跳转返回ModelAndView
User user = userService.login(loginCommand.getUserName(),loginCommand.getPassword());
if(user!=null){
userService.doLog(user);
request.getSession().setAttribute("user", user);
return new ModelAndView("main");
}
return new ModelAndView("login","error","用户名或密码错误");
}
}
下面可以写jsp页面啦!终于要写完啦~
<body>
<div>${error}</div>
<div>
<form action='<c:url value="/login.html"/>' method="post">
用户名:<input type="text" name="userName" /><br/>
密 码:<input type="password" name="password" /><br/>
<input type="submit" value="提交" />
</form>
</div>
EL表达式显示动态值
欢迎页面:
<div>
欢迎您!${user.name}
</div>
总体来看,用spring开发时非常轻快,没有继承庞大的父类,没有实现复杂的接口,页面跳转也非常简洁,想要对象就注解一下,直接拿来用…崇尚简单就是spring的风格。
第一篇就到这里吧,叙述欠妥之处望高手谅解,也请不吝指点。