1.涉及基础的SpringMVC /SpringJDBC / Spring
2.spring4.0.4版本 tomcat7 mysql IDE:eclipse
3.项目结构
4.源码
建表语句
CREATE TABLE `t_login_log` (
`login_log_id` int(11) NOT NULL auto_increment,
`user_id` int(11) default NULL,
`ip` varchar(23) default NULL,
`login_datetime` datetime default NULL,
PRIMARY KEY (`login_log_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_user` (
`user_id` int(11) NOT NULL auto_increment,
`user_name` varchar(30) default NULL,
`credits` int(11) default NULL COMMENT '用户积分',
`password` varchar(32) default NULL,
`last_visit` datetime default NULL,
`last_ip` varchar(23) default NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
LoginLog.java User.java实体类(省略getter setter)
public class LoginLog implements Serializable{
private int loginLogId;
private int userId;
private String ip;
private Date loginDate;
}
public class User implements Serializable{
private int userId;
private String userName;
private String passWord;
private int credits;
private String lastIp;
private Date lastVisit;
}
LoginLogDao.java
package com.cityeve.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.cityeve.domain.LoginLog;
@Repository
public class LoginLogDao {
private JdbcTemplate jdbcTemplate;
@Autowired //自动注入JdbcTemplate的bean
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate=jdbcTemplate;
}
//保存登陆日志SQL
private final static String INSERT_LOGIN_SQL="insert into "
+ "t_login_log(user_id,ip,login_datetime) values(?,?,?)";
public void insertLoginLog(LoginLog loginLog){
System.out.println("进来了");
Object [] arg={loginLog.getUserId(),loginLog.getIp(),loginLog.getLoginDate()};
jdbcTemplate.update(INSERT_LOGIN_SQL,arg);
}
}
UserDao.java
package com.cityeve.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Repository;
import com.cityeve.domain.User;
@Repository //通过spring注解定义一个Dao
public class UserDao {
private JdbcTemplate jdbcTemplate;
@Autowired //自动注入JdbcTemplate的bean
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate=jdbcTemplate;
}
public int getMatchCount(String userName,String password){
String sqlStr="select count(*) from t_user where user_name=? and password=?";
return jdbcTemplate.queryForObject(sqlStr, new Object[]{userName,password},Integer.class);
}
//根据用户名查询用户的sql语句
private final static String MATCH_COUNT_SQL="select * from "
+ " t_user where user_name=?";
private final static String UPDATE_LOGIN_INFO_SQL="update t_user set "
+ " last_visit=?,last_ip=?,credits=? where user_id=?";
//通过用户名查询用户
public User findUserByUserName(final String userName){
final User user=new User();
jdbcTemplate.query(MATCH_COUNT_SQL,new Object[]{userName},
new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
user.setUserId(rs.getInt("user_id"));
user.setUserName(userName);
user.setCredits(rs.getInt("credits"));
}
});
return user;
}
//修改用户信息
public void updateLoginInfo(User user){
jdbcTemplate.update(UPDATE_LOGIN_INFO_SQL,new Object[]{user.getLastVisit(),
user.getUserId(),user.getCredits(),user.getUserId()});
}
}
UserService.java
package com.cityeve.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.cityeve.dao.LoginLogDao;
import com.cityeve.dao.UserDao;
import com.cityeve.domain.LoginLog;
import com.cityeve.domain.User;
@Service //将UserService标注为一个服务的Bean
public class UserService {
private UserDao userDao;
private LoginLogDao loginLogDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Autowired
public void setLoginLogDao(LoginLogDao loginLogDao) {
this.loginLogDao = loginLogDao;
}
public boolean hasMatchUser(String userName,String password){
int matchCount=userDao.getMatchCount(userName, password);
return matchCount>0;
}
public User findUserByUserName(String userName){
return userDao.findUserByUserName(userName);
}
//执行增删改放在事务中
@Transactional
public void loginSuccess(User user){
user.setCredits(5+user.getCredits());
LoginLog loginLog=new LoginLog();
loginLog.setUserId(user.getUserId());
loginLog.setIp(user.getLastIp());
loginLog.setLoginDate(user.getLastVisit());
userDao.updateLoginInfo(user);
loginLogDao.insertLoginLog(loginLog);
}
}
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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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">
<!-- 1.扫描类包,将标注spring注解的类自动转化为bean,同时完成bean注入 -->
<!-- 使用spring的context-component-span扫描置顶类包下所有类,这样类中定义的spring注解如@repository、@AutoWired等才能产生作用 -->
<context:component-scan base-package="com.cityeve.dao"/>
<!-- 扫描service类包,应用spring的注解配置 -->
<context:component-scan base-package="com.cityeve.service"/>
<!-- 2.定义一个dbcp实现的数据源,DBCP开源数据源实现方案 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/sampledb"
p:username="root"
p:password="root"/>
<!--3.定义jdbc模板bean -->
<!--配置JdbcTemplate Bean,将上面声明的dataSource注入到jdbcTemplate中。而这个jdbcTemplate bean将通过
@Autowired自动注入到LoginLog和UserDao的Bean中,可见spring可以很好的将注解配置和xml配置统一起来 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"/>
<!-- 4.配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<!-- 5.通过Aop配置提供事务增强,让service包下所有Bean的所有方法拥有事务(上面的tx和aop的xsd文件),spring事务配置详见spring4.x企业应用开发实战第11章 -->
<!-- 通过AOP配置提供事务增强,让service包下所有Bean的所有方法拥有事务 -->
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceMethod"
expression="execution(* com.cityeve.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>
</beans>
springmvc.xml
<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"
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/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
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 ">
<!-- 自动扫描包下面的文件,类上带有@Controller的会注册为bean -->
<context:component-scan base-package="com.cityeve.controller"></context:component-scan>
<!-- 代替处理器映射器、处理器适配器 ,mvc注解驱动-->
<!-- 如果没有<annotation-driven/>, <resource/> 元素会阻止任意控制器被调用, 若不要使用resources, 则不需要<annotation-driven/>元素’ 还有 如果不是用resource 就没必要用<annotation-driven/> -->
<mvc:annotation-driven/>
<!-- 视图解析器,将modelandview和字符串解析为具体的页面 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置jsp路径的前缀,后缀,那样在controller中设置视图时候不需要再加了 -->
<!-- prefix前缀如果 不添加,那么如果在@controller注解下有一个@requestmapping("name")访问时候会出错-->
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
log4j.properties 里面是空的,基础的这儿没用到,我也不会log4j
AllTests.java junit测试,可以不要
package com.cityeve.test;
import static 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 com.cityeve.domain.User;
import com.cityeve.service.UserService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:/applicationContext.xml"})
public class AllTests {
@Autowired
UserService userService;
@Test
public void hasMatchUser(){
//Boolean b1=userService.hasMatchUser("塔睿", "12345");
Boolean b2=userService.hasMatchUser("taray", "123456");
//assertTrue(b1);
assertTrue(b2);
}
@Test
public void findUserByUserName(){
User user=userService.findUserByUserName("xiaji");
assertEquals(user.getUserName(), "xiaji");
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<!-- 设置web容器启动时能够自动启动spring容器,(1)处多个配置文件可用逗号或空格分隔,建议用逗号。(2)处指定spring所提供的ContextLoaderListener的web容器监听器,该监听器在web容器启动时自动运行,它会根据contextConfigLocation Web容器参数获取Spring配置文件,并启动spring容器 -->
<!-- (1)从类路径下加载spring配置文件,classpath关键字特指类路径下加载 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- (2)负责启动spring容器的监听器,引用(1)处上下文参数获得的spring配置文件地址 -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 配置spring mvc,spring mvc像struts一样,也通过一个Servlet来截获URL请求,然后再进行相关的处理 -->
<!-- spring MVC的主控Servlet -->
<servlet>
<servlet-name>cityeve</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载springmvc配置文件 ,没有以下上下文配置位置,会读取一个默认的名字,那样springmvc配置文件名要符合规范-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- spring mvc处理的url -->
<servlet-mapping>
<servlet-name>cityeve</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
</web-app>
LoginController.java
package com.cityeve.controller;
import java.util.Date;
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 com.cityeve.domain.User;
import com.cityeve.service.UserService;
@Controller
public class LoginController {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
@RequestMapping("index.htm")
public String loginPage(){
return "login";
}
@RequestMapping("loginCheck")
public ModelAndView loginCheck(HttpServletRequest request,User user){
boolean isValidUser=userService.hasMatchUser(user.getUserName(), user.getPassWord());
if(!isValidUser){
return new ModelAndView("login","error","用户名或密码错误!");
}else{
User user2=userService.findUserByUserName(user.getUserName());
user2.setLastIp(request.getLocalAddr());
user2.setLastVisit(new Date());
userService.loginSuccess(user2);
request.getSession().setAttribute("user", user2);
return new ModelAndView("main");
}
}
}
login.jsp
<%@ page language="java" import="java.util.Map" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.6.4/jquery.min.js"></script>
<link href="http://libs.baidu.com/bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
<script src="http://libs.baidu.com/bootstrap/2.3.2/js/bootstrap.min.js"></script>
</head>
<body>
<form action="<%=basePath %>loginCheck.htm" method="post">
<table>
<tr>
<td>name:</td>
<td><input type="text" value="" name="userName" placeholder="输入name"/></td>
</tr>
<tr>
<td>password:</td>
<td><input type="text" value="" name="passWord" placeholder="输入password"/></td>
</tr>
</table>
<input type="submit" value="提交"/>
</form>
</body>
</html>
main.jsp
<%@ page language="java" import="java.util.Map" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.6.4/jquery.min.js"></script>
<link href="http://libs.baidu.com/bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
<script src="http://libs.baidu.com/bootstrap/2.3.2/js/bootstrap.min.js"></script>
</head>
<body>
<h1>${user.userName }主页!</h1>
</body>
</html>