SpringMVC+JdbcTemplate注解开发demo
1、环境描述
本文目标:使用Spring框架的JdbcTemplate和阿里的druid数据库连接池整合SpringMVC。全称使用注解开发模式(零xml配置)。
- maven 3.6版本
- spring 5.x版本
- servlet 3.1版本
- mysql 8.x版本
1.1 项目结构
1.2 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.feng</groupId>
<artifactId>springmvc-publisher</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>springmvc-publisher Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.2.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
</dependencies>
<build>
<finalName>springmvc-publisher</finalName>
</build>
</project>
1.3 jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/springmvc?characterEncoding=utf-8&serverTimezone=UTC
jdbc.username=root
jdbc.password=root
1.4 log4j.properties
# Set root category priority to INFO and its only appender to CONSOLE.
log4j.rootCategory=INFO, CONSOLE
#log4j.rootCategory=INFO, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=INFO
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %m%n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.Threshold=INFO
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
2、java代码
首先是配置类:用于替换之前在框架搭建时用的xml文件。
2.1 JDBC的配置类
package org.feng;
import com.alibaba.druid.pool.DruidDataSource;
import com.mysql.cj.jdbc.Driver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.sql.SQLException;
/**
* Created by Feng on 2019/12/19 17:35
* CurrentProject's name is springmvc-publisher
* JDBC配置类
* @author Feng
*/
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(JdbcConfig.class);
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 装配{@link DataSource}到spring容器
* @return DataSource对象
*/
@Bean(name = "dataSource")
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
try {
dataSource.setDriver(new Driver());
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
} catch (SQLException e) {
LOGGER.error("getting datasource error...", e);
}
return dataSource;
}
/**
* 装配{@link JdbcTemplate}到spring容器
* @param dataSource 数据源
* @return JdbcTemplate对象
*/
@Bean(name = "jdbcTemplate")
public JdbcTemplate createJdbcTemplate(DataSource dataSource){
LOGGER.info("creating JdbcTemplate...");
return new JdbcTemplate(dataSource);
}
}
2.2 Spring的配置类
package org.feng;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Controller;
/**
* Created by Feng on 2019/12/19 17:34
* CurrentProject's name is springmvc-publisher
* Spring的配置类:不扫描{@link Controller}
* @author Feng
*/
@Configuration
@ComponentScan(value = "org.feng", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes =
Controller.class))
@Import(JdbcConfig.class)
public class SpringConfig {
}
2.3 SpringMVC的配置类
package org.feng;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
/**
* Created by Feng on 2019/12/19 19:28
* CurrentProject's name is springmvc-publisher
* Springmvc的配置类:用于替代springmvc.xml文件
* @author Feng
*/
@Configuration
@ComponentScan(value = "org.feng.controller")
public class SpringMvcConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringConfig.class);
/**
* 创建视图解析器:设置前缀+后缀,存入IOC容器
* @return 视图解析器
*/
@Bean
public ViewResolver createViewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
LOGGER.info("set viewResolver over");
return viewResolver;
}
}
2.4 配置类整合
package org.feng;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
/**
* Created by Feng on 2019/12/19 19:40
* CurrentProject's name is springmvc-publisher
* 初始化spring和springmvc ioc容器的配置类:在spring框架前执行
* @author Feng
*/
public class Config extends AbstractDispatcherServletInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger(Config.class);
/**
* 重写方法:注册字符集过滤器
* @param servletContext
* @throws ServletException
*/
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
// 创建字符集过滤器
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
// 设置使用的字符集
characterEncodingFilter.setEncoding("UTF-8");
// 添加到容器(不是IOC容器)
servletContext.addFilter("characterEncodingFilter", characterEncodingFilter);
LOGGER.info("set characterEncodingFilter to utf-8");
}
/**
* 用于创建SpringMVC的ioc容器
* @return 注册了springmvc配置的上下文类
*/
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext acw = new AnnotationConfigWebApplicationContext();
// 注册SpringMVC的配置类
acw.register(SpringMvcConfig.class);
LOGGER.info("register org.feng.SpringMvcConfig.class");
return acw;
}
/**
* 用于指定DispatcherServlet的请求映射
* @return 字符串数组;相当于在web.xml配置时的mapping路径
*/
@Override
protected String[] getServletMappings() {
LOGGER.info("mapping to servlet[*.do][*.action]");
return new String[]{"*.do", "*.action"};
}
/**
* 用于创建Spring的ioc容器
* @return 注册了Spring配置的上下文类
*/
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext acw = new AnnotationConfigWebApplicationContext();
// 注册Spring的配置
acw.register(SpringConfig.class);
LOGGER.info("register org.feng.SpringConfig.class");
return acw;
}
}
2.5 实体类
package org.feng.entity;
import java.io.Serializable;
import java.util.Date;
/**
* Created by Feng on 2019/12/19 17:50
* CurrentProject's name is springmvc-publisher
* @author Feng
*/
public class Publisher implements Serializable {
private static final long serialVersionUID = -2069618414619440779L;
@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
private Integer pub_id;
private String pub_name;
private String pub_address;
private String pub_phone;
private String pub_contact;
private Date pub_date;
public Integer getPub_id() {
return pub_id;
}
public void setPub_id(Integer pub_id) {
this.pub_id = pub_id;
}
public String getPub_name() {
return pub_name;
}
public void setPub_name(String pub_name) {
this.pub_name = pub_name;
}
public String getPub_address() {
return pub_address;
}
public void setPub_address(String pub_address) {
this.pub_address = pub_address;
}
public String getPub_phone() {
return pub_phone;
}
public void setPub_phone(String pub_phone) {
this.pub_phone = pub_phone;
}
public String getPub_contact() {
return pub_contact;
}
public void setPub_contact(String pub_contact) {
this.pub_contact = pub_contact;
}
public Date getPub_date() {
return pub_date;
}
public void setPub_date(Date pub_date) {
this.pub_date = pub_date;
}
@Override
public String toString() {
return "Publisher{" +
"pub_id=" + pub_id +
", pub_name='" + pub_name + '\'' +
", pub_address='" + pub_address + '\'' +
", pub_phone='" + pub_phone + '\'' +
", pub_contact='" + pub_contact + '\'' +
", pub_date=" + pub_date +
'}';
}
}
2.6 数据访问层接口和类
package org.feng.dao;
import org.feng.entity.Publisher;
import java.util.List;
/**
* Created by Feng on 2019/12/19 17:55
* CurrentProject's name is springmvc-publisher
* @author Feng
*/
public interface PublisherDao {
/**
* 查询所有的publisher
* @return publisher集合
*/
List<Publisher> listPublisher();
/**
* 修改 publisher
* @param publisher 实体
* @return 修改结果;影响行数
*/
int updatePublisher(Publisher publisher);
/**
* 增加 publisher
* @param publisher 实体
* @return 结果;影响行数
*/
int insertPublisher(Publisher publisher);
/**
* 删除 publisher
* @param publisher 实体
* @return 结果;影响行数
*/
int deletePublisher(Publisher publisher);
}
package org.feng.dao.impl;
import org.feng.dao.PublisherDao;
import org.feng.entity.Publisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Created by Feng on 2019/12/19 17:57
* CurrentProject's name is springmvc-publisher
* 数据访问实现:对表publisher进行操作
* @author Feng
*/
@Component("publisherDao")
public class PublisherDaoImpl implements PublisherDao {
private final JdbcTemplate jdbcTemplate;
@Autowired
public PublisherDaoImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public List<Publisher> listPublisher() {
String sql = "select pub_id, pub_name, pub_address, pub_phone, pub_contact, pub_date from publisher";
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Publisher.class));
}
@Override
public int updatePublisher(Publisher publisher) {
String sql = "update publisher set pub_name = ?, pub_address = ?, pub_phone = ?, pub_contact = ?, pub_date = " +
"? where pub_id = ?";
return jdbcTemplate.update(sql, publisher.getPub_name(), publisher.getPub_address(),
publisher.getPub_phone(), publisher.getPub_contact(), publisher.getPub_date(), publisher.getPub_id());
}
@Override
public int insertPublisher(Publisher publisher) {
String sql = "insert into publisher(pub_name, pub_address, pub_phone, pub_contact, pub_date) values (?,?,?,?," +
"?)";
return jdbcTemplate.update(sql, publisher.getPub_name(), publisher.getPub_address(), publisher.getPub_phone()
, publisher.getPub_contact(), publisher.getPub_date());
}
@Override
public int deletePublisher(Publisher publisher) {
String sql = "delete from publisher where pub_id = ?";
return jdbcTemplate.update(sql, publisher.getPub_id());
}
}
2.7 业务层接口和类
package org.feng.service;
import org.feng.entity.Publisher;
import java.util.List;
/**
* Created by Feng on 2019/12/19 18:06
* CurrentProject's name is springmvc-publisher
* @author Feng
*/
public interface PublisherService {
/**
* 查询所有的publisher
* @return publisher集合
*/
List<Publisher> listPublisher();
/**
* 修改 publisher
* @param publisher 实体
* @return 修改结果;影响行数
*/
int updatePublisher(Publisher publisher);
/**
* 增加 publisher
* @param publisher 实体
* @return 结果;影响行数
*/
int insertPublisher(Publisher publisher);
/**
* 删除 publisher
* @param publisher 实体
* @return 结果;影响行数
*/
int deletePublisher(Publisher publisher);
}
package org.feng.service.impl;
import org.feng.dao.PublisherDao;
import org.feng.entity.Publisher;
import org.feng.service.PublisherService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created by Feng on 2019/12/19 18:08
* CurrentProject's name is springmvc-publisher
* @author Feng
*/
@Service
public class PublisherServiceImpl implements PublisherService {
private static final Logger LOGGER = LoggerFactory.getLogger(PublisherServiceImpl.class);
private final PublisherDao publisherDao;
@Autowired
public PublisherServiceImpl(PublisherDao publisherDao) {
LOGGER.info(PublisherServiceImpl.class + " get " + PublisherDao.class);
this.publisherDao = publisherDao;
}
@Override
public List<Publisher> listPublisher() {
return publisherDao.listPublisher();
}
@Override
public int updatePublisher(Publisher publisher) {
return publisherDao.updatePublisher(publisher);
}
@Override
public int insertPublisher(Publisher publisher) {
return publisherDao.insertPublisher(publisher);
}
@Override
public int deletePublisher(Publisher publisher) {
return publisherDao.deletePublisher(publisher);
}
}
2.8 控制器类
package org.feng.controller;
import org.feng.service.PublisherService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* Created by Feng on 2019/12/19 20:21
* CurrentProject's name is springmvc-publisher
* @author Feng
*/
@Controller
@RequestMapping("/publisher")
public class PublisherController {
private static final Logger LOGGER = LoggerFactory.getLogger(PublisherController.class);
private final PublisherService publisherService;
@Autowired
public PublisherController(PublisherService publisherService) {
LOGGER.info(PublisherController.class + " get " + PublisherService.class);
this.publisherService = publisherService;
}
@RequestMapping("/list.do")
public ModelAndView listPublishers(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("publisherList", publisherService.listPublisher());
modelAndView.setViewName("/success");
return modelAndView;
}
}
3、页面
success.jsp
<%@page isELIgnored="false" pageEncoding="UTF-8" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<h2>出版社列表</h2>
<div>
<table>
<tr>
<th>编号</th>
<th>出版社名</th>
<th>地址</th>
<th>电话</th>
<th>联系人</th>
<th>成立日期</th>
<th>操作</th>
</tr>
<c:forEach items="${publisherList}" var="publisher" varStatus="status">
<tr>
<td>${status.count}</td>
<td>${publisher.pub_name}</td>
<td>${publisher.pub_address}</td>
<td>${publisher.pub_phone}</td>
<td>${publisher.pub_contact}</td>
<td>${publisher.pub_date}</td>
<td><a href="#">删除</a> <a href="#">修改</a></td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
4、Tomcat配置和结果
测试类(注意放在test/java中)
package org.feng.service;
import org.feng.SpringConfig;
import org.feng.entity.Publisher;
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;
/**
* Created by Feng on 2019/12/19 18:14
* CurrentProject's name is springmvc-publisher
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class ServiceTest {
@Autowired
private PublisherService publisherService;
@Test
public void testQueryAll(){
publisherService.listPublisher().forEach(System.out::println);
}
@Test
public void testInsert(){
Publisher publisher = new Publisher();
publisher.setPub_name("xiao风出版社");
publisher.setPub_address("西安");
publisher.setPub_contact("小冯");
publisher.setPub_date(new Date());
publisher.setPub_phone("18142395136");
System.out.println(publisherService.insertPublisher(publisher));
}
}