在classpath下新建一个.properties属性文件,里面写好数据库的相关信息:
注意里面的url的“\:”是转义字符,driver是通过解压工具打开驱动jar查看的Driver.class的路径,在这里注意要把驱动jar包添加到tomcat的lin下,只单单是放在项目下会出现找不到的错误,可能你放在WEB-INF下的lib中应该也能行,不妨试试。
2.新建JdbcDataSource类,封装数据库信息:
使用@Value("#表达式")来把.properties里的相关值映射进来。当然,在这之前,你需要在applicationContext.xml(可自定义名字)中开启注解扫描,并且配置properties文件:
说到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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
">
<mvc:annotation-driven/>
<context:component-scan base-package="com"/>
<util:properties id="jdbcProps" location="classpath:db.properties"></util:properties>
<bean id="handler" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings" ref="map1"/>
</bean>
<util:properties id="map1">
<prop key="/hello.do">helloController</prop>
</util:properties>
<bean id="helloController" class="com.hardy.test.HelloController"/>
<bean id="resolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> -->
</beans>
这里面的handler和map1的部分是配置文件中实现的url映射,当使用url地址访问的时候,首先DispatcherServlet会去交给SimpleHandlerMapping,他负责去查找该url所指向的JavaBean,再来看HelloController:
resolver是处理结果视图显示器,他负责根据你返回的视图文件(如jsp)名字的字符串或者ModelAndView(注意一定是servlet包下的,不是portlet包下的那个),去按照prefix和suffix去拼凑完整路径,然后去找到相关的显示文件去返回。
再去看一下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" version="3.0">
<display-name>Demo1</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 解决中文乱码 -->
<filter>
<filter-name>encodingFilter</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>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
其中的context-param配置好spring的配置文件路径,我们这里是applicationContext.xml,这个名字自己可以任意起。
servlet配置了DispatcherServlet,这里是整个springMVC框架的入口,配置了这个,指定的url都会先交给DispatcherServlet来处理,在这里指定的是所有url,代表所有的是“/”,而不是“/*”,否则会出现404,可能是spring要求吧。
filter可以实现在获取参数之前事先进行处理,这里处理的是编码格式,解决中文乱码,而且这里指定的所有的url是用“/*”,而不是"/",否则会进不去filter。
好了,前面的是通过applicationContext.xml配置url映射,现在我们通过注解来实现:
我们在mysql数据库下新建一个person数据库,新建一张person表:
插入几条数据:
建立相关实体类:
package com.hardy.test;
import java.io.Serializable;
public class Person implements Serializable {
private int id;
private String name ;
private int age ;
private String sex ;
private int height ;
private int weight ;
private String phone ;
private String address ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
建立数据库操作接口:
package com.hardy.test;
public interface PersonDao {
public Person findPersonByName(String name);
}
这里只定义一个查找根据name查找person的操作。
实现Dao层:
package com.hardy.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
@Repository("personDao")
public class MySqlDaoImpl implements PersonDao {
private JdbcDataSource dataSource ;
public JdbcDataSource getDataSource() {
return dataSource;
}
@Autowired
public void setDataSource(@Qualifier("jdbcDataSource") JdbcDataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Person findPersonByName(String name) {
String sql = "select id,name,age,sex,height,weight,phone,address from person where name=? ";
Connection conn = dataSource.getConnection();
PreparedStatement ps;
Person person = new Person();
ResultSet rs = null ;
try {
ps = conn.prepareStatement(sql);
ps.setString(1,name);
rs = ps.executeQuery();
while(rs.next()){
person.setId(rs.getInt("id"));
person.setName(rs.getString("name"));
person.setAge(rs.getInt("age"));
person.setSex(rs.getString("sex"));
person.setHeight(rs.getInt("height"));
person.setWeight(rs.getInt("weight"));
person.setPhone(rs.getString("phone"));
person.setAddress(rs.getString("address"));
}
ps.close();
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
dataSource.close(conn);
}
return person;
}
}
先定义数据库操作接口的其中一个目的是便于扩展,假如我们现在想更换成Oracle数据库,那么我们只需要再创建一个类实现Dao接口,只不过里面的JdbcDataSource换成Oracle的即可。
感觉代码还不够简洁,所以我们还需要定义一个Service类进一步封装这些业务代码:
package com.hardy.test;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class PersonService {
@Resource(name="personDao")
private PersonDao personDao ;
public PersonDao getPersonDao() {
return personDao;
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
public Person login(String name,String sex) throws NullParamException,NameOrPwdException{
if(name == null || "".equals(name) || sex == null || "".equals(sex)){
throw new NullParamException("登录参数不能为空!");
}
Person person = personDao.findPersonByName(name);
if(person != null && sex.equals(person.getSex())){
// System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@");
return person;
}
throw new NameOrPwdException("名字或性别错误!");
}
}
到这里其实代码足够简洁了,但我们还需要针对正确的结果和错误的异常做出进一步的处理,比如返回正常结果或者跳转到指定错误页,主要是spring需要通过实现了Controller接口的类来进入我们实现的业务逻辑。所以我们还需要定义一个Controller类:
package com.hardy.test;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/login")
public class LoginController {
@Resource
private PersonService personService ;
public PersonService getPersonService() {
return personService;
}
public void setPersonService(PersonService personService) {
this.personService = personService;
}
@RequestMapping("/login.do")
public String toLogin(){
return "login-form";
}
/**
* 最基本的通过HttpServletRequest获取参数
* @param request
* @return
*/
@RequestMapping("/login-action1.do")
public String checkLogin1(HttpServletRequest request){
String tempName = request.getParameter("name");
String tempSex = request.getParameter("sex");
//因为Tomcat默认编码是ISO-8859-1
String name = null;
String sex = null ;
try {
name = new String(tempName.getBytes("ISO-8859-1"), "utf-8");
sex = new String(tempSex.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
Person person = personService.login(name, sex);
request.getSession().setAttribute("user", person);
return "success";
} catch (NullParamException e) {
// TODO Auto-generated catch block
e.printStackTrace();
request.setAttribute("message", e.getMessage());
return "login-form";
} catch (NameOrPwdException e) {
// TODO Auto-generated catch block
e.printStackTrace();
request.setAttribute("message", e.getMessage());
return "redirect:login-form";
}
}
/**
*
* @param name 参数名和表单input的那么属性值一致即可自动注入参数
* @param tempSex 通过RequestParam()实现不同参数名的参数注入
* @param req
* @return
*/
@RequestMapping("/login-action2.do")
public String checkLogin2(String name,@RequestParam("sex") String tempSex,HttpServletRequest req){
try {
Person person = personService.login(name, tempSex);
req.getSession().setAttribute("user", person);
return "success";
} catch (NullParamException e) {
// TODO Auto-generated catch block
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "login-form";
} catch (NameOrPwdException e) {
// TODO Auto-generated catch block
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "login-form";
}
}
/**
*
* @param per 实体类参数自动注入(会按照表单name属性值匹配Person类的相关setter方法注入参数)
* @param req
* @return
*/
@RequestMapping("/login-action3.do")
public String checkLogin3(Person per,HttpServletRequest req){
try {
Person person = personService.login(per.getName(), per.getSex());
req.getSession().setAttribute("user", person);
return "success";
} catch (NullParamException e) {
// TODO Auto-generated catch block
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "login-form";
} catch (NameOrPwdException e) {
// TODO Auto-generated catch block
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "login-form";
}
}
/**
* 使用ModelAndView向跳转页面传值
* @return
*/
@RequestMapping("/login-action4.do")
public ModelAndView checkLogin4(String name,String sex,HttpServletRequest req){
Map<String,Object> data = new HashMap<String,Object>();
try {
Person person = personService.login(name, sex);
// req.getSession().setAttribute("user", person);
// return "success";
data.put("user", person);
return new ModelAndView("success", data);
} catch (NullParamException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// req.setAttribute("message", e.getMessage());
// return "login-form";
data.put("message", e.getMessage());
return new ModelAndView("login-form", data);
} catch (NameOrPwdException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// req.setAttribute("message", e.getMessage());
// return "login-form";
data.put("message", e.getMessage());
return new ModelAndView("login-form", data);
}
}
/**
* 使用ModelMap向跳转页面传值,ModelMap和HttpServletRequest类似,伴随着整个请求,所以只需要获取,然后赋值即可
* @return
*/
@RequestMapping("/login-action5.do")
public String checkLogin5(String name,String sex,ModelMap model,HttpServletRequest req){
Map<String,Object> data = new HashMap<String,Object>();
try {
Person person = personService.login(name, sex);
req.getSession().setAttribute("user", person);
return "success";
} catch (NullParamException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// req.setAttribute("message", e.getMessage());
model.addAttribute("message", e.getMessage());
return "login-form";
} catch (NameOrPwdException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// req.setAttribute("message", e.getMessage());
model.addAttribute("message", e.getMessage());
return "login-form";
}
}
/**
* 使用ModelMap向跳转页面传值,ModelMap和HttpServletRequest类似,伴随着整个请求,所以只需要获取,然后赋值即可
* @return
*/
@RequestMapping("/login-action6.do")
public String checkLogin6(@ModelAttribute("name") String name,@ModelAttribute("sex") String sex,ModelMap model,HttpServletRequest req){
Map<String,Object> data = new HashMap<String,Object>();
try {
Person person = personService.login(name, sex);
req.getSession().setAttribute("user", person);
return "success";
} catch (NullParamException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// req.setAttribute("message", e.getMessage());
model.addAttribute("message", e.getMessage());
return "login-form";
} catch (NameOrPwdException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// req.setAttribute("message", e.getMessage());
model.addAttribute("message", e.getMessage());
return "login-form";
}
}
private String[] msgs = {"One More!","下次会成功的!","没关系还有机会!"};
@ModelAttribute("next")
public String getNext(){
Random rd = new Random();
return msgs[rd.nextInt(3)];
}
}
首先,我们这里不用再实现Controller接口了,我们也不需要在applicationContext.xml里面配置Controller和SimpleHandlerMapping了,我们只需要添加@Controller注解即可,剩下的交给spring去做,此外添加@RequestMapping(“路径名”),我们就可以按照这个路径名去访问这个类了。这里我们实现了几个方法,每个方法前面RequestMapping指定的路径加上前面类上面的RequestMapping路径就是访问方法里面逻辑的url,比如“http://localhost:8080/项目名/login/login-action1”就会去执行checkLogin1()这个方法里的逻辑。这几个方法分别代表了几种不同的获取参数和返回的方式,看一下注解就会明白,特别说一下最后的@ModelAttribute(“表单中表达式的名字”),这个注解的作用就是当执行完此次请求的处理之后返回时,被这个注解修饰的属性或者方法的返回值就会被赋值到表单的指定表达式中显示出来,下面是包含多个表单的jsp页面:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<c:url var="base" value="/"></c:url>
<html>
<head>
<title>My JSP 'login-form.jsp' starting page</title>
<link rel="stylesheet" type="text/css" href="${base}styles.css"/>
</head>
<body>
<h6>${message}</h6>
<form method="post" action="${base}login/login-action1.do">
<div>
<h2>登录 login-action1.do</h2>
<p><label>名字</label><input type="text" name="name"/></p>
<p><label>性别</label><input type="text" name="sex"/></p>
<h3><input type="submit" value="登录"/></h3>
</div>
</form>
<form method="post" action="${base}login/login-action2.do">
<div>
<h2>登录 login-action2.do</h2>
<p><label>名字</label><input type="text" name="name"/></p>
<p><label>性别</label><input type="text" name="sex"/></p>
<h3><input type="submit" value="登录"/></h3>
</div>
</form>
<form method="post" action="${base}login/login-action3.do">
<div>
<h2>登录 login-action3.do</h2>
<p><label>名字</label><input type="text" name="name"/></p>
<p><label>性别</label><input type="text" name="sex"/></p>
<h3><input type="submit" value="登录"/></h3>
</div>
</form>
<form method="post" action="${base}login/login-action4.do">
<div>
<h2>登录 login-action4.do</h2>
<p><label>名字</label><input type="text" name="name"/></p>
<p><label>性别</label><input type="text" name="sex"/></p>
<h3><input type="submit" value="登录"/></h3>
</div>
</form>
<form method="post" action="${base}login/login-action5.do">
<div>
<h2>登录 login-action5.do</h2>
<p><label>名字</label><input type="text" name="name"/></p>
<p><label>性别</label><input type="text" name="sex"/></p>
<h3><input type="submit" value="登录"/></h3>
</div>
</form>
<form method="post" action="${base}login/login-action6.do">
<div>
<h2>登录 login-action6.do</h2>
<h5>${next}</h5>
<p><label>名字</label><input type="text" name="name" value="${name}"/></p>
<p><label>性别</label><input type="text" name="sex"/></p>
<h3><input type="submit" value="登录"/></h3>
</div>
</form>
</body>
</html>
在这里,${next}就会显示msgs[rd.nextInt(3)]的值,而${name}会显示方法参数中name的值(在这里呈现的效果相当于记住名字)。