开始折腾SpringBoot,需要配置的东西不多,相比Spring原有的一大堆maven依赖来说,简直是web开发利器!一个登陆页面为例,以此记录。
准备
maven配置
新建一个maven项目,不用多说,配置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">
<!-- 直接继承父类,记得添加最后的repository标签的内容-->
<!-- 也可以自己指定SpringBoot依赖包的版本号 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springboot</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- 一个很好用的注解插件,需要在IDEA-Setting-Plugin中安装lombok插件才能用 -->
<!-- 也可以不加入这个依赖包,用传统方式生成getter和setter -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
<scope>provided</scope>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- spring boot -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!-- spring boot -->
<!-- Add Spring repositories -->
<!-- (you don't need this if you are using a .RELEASE version) -->
<repositories>
<repository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
<snapshots><enabled>true</enabled></snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
</project>
数据库配置
插两张表和一条记录
CREATE TABLE IF NOT EXISTS t_user(
user_id INT AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(30),
credits INT,
password VARCHAR(32),
last_visit datetime,
last_ip VARCHAR(23)
)ENGINE=InnoDB;
CREATE TABLE t_login_log(
login_log_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
ip VARCHAR(23),
login_datetime datetime
)ENGINE=InnoDB;
INSERT INTO t_user(user_name, password)VALUES('admin','123456');
然后在项目中添加application.properties文件,配置数据库信息。
spring.datasource.url=jdbc:mysql://localhost:3306/webstudy
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.max-wait=10000
spring.datasource.max-active=50
spring.datasource.max-idle=10
spring.datasource.min-idle=8
spring.datasource.test-on-borrow=true
spring.datasource.validation-query=select 1
# 指定视图路径的前缀
spring.mvc.view.prefix=/WEB-INF/jsp/
# 指定视图文件的后缀
spring.mvc.view.suffix=.jsp
项目文件结构
dao层:负责直接和数据库中的数据打交道。
domain:VO或SO,主要是出参入参的数据结构类。
service:业务逻辑层,带事务的逻辑一般都放在这层。
controller:web页面跳转控制。
右击项目名称->Add Framework Support -> 添加Web Application模块。
要注意的是:IDEA自动添加的web模块位置需要调整一下,不然会报找不到jps文件的错误。web目录结构如下。
代码
此案例用最基本的JDBC和数据库交互,习惯性先写domain层,简单暴力。(如果用mybatis可以自动生成mapping文件)
domain层
User.java
public class User implements Serializable {
//lombok注解工具,也可以直接使用传统的方法生成getter和setter
@Getter @Setter
private int userId;
@Getter @Setter
private String userName;
@Getter @Setter
private int credits;
@Getter @Setter
private String lastIp;
@Getter @Setter
private Date lastVisit;
}
LoginLog.java
public class LoginLog implements Serializable {
@Getter @Setter
private int loginLogId;
@Getter @Setter
private int userId;
@Getter @Setter
private String ip;
@Getter @Setter
private Date loginDate;
}
LoginCommand.java
//登录使用的入参,后面会用到
public class LoginCommand {
@Getter @Setter
private String userName;
@Getter @Setter
private String password;
}
dao层
UserDao.java
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
private final static String MATCH_COUNT_SQL = "SELECT count(*) FROM t_user WHERE user_name=? AND password=?";
private final static String UPDATE_LOGIN_INFO_SQL =
"UPDATE t_user SET last_visit=?, last_ip=?, credits=?, WHERE user_id=?";
//查询数据库中是否存在相应用户
public int getMatchCount(String userName, String password){
return jdbcTemplate.queryForObject(MATCH_COUNT_SQL, new Object[] {userName, password}, Integer.class);
}
//根据用户名查询用户信息
public User findUserByUserName(final String userName){
final User user = new User();
jdbcTemplate.query(MATCH_COUNT_SQL, new Object[]{userName}, new RowCallbackHandler() {
public void processRow(ResultSet resultSet) throws SQLException {
user.setUserId(resultSet.getInt("user_id"));
user.setUserName(userName);
user.setCredits(resultSet.getInt("credits"));
}
});
return user;
}
//用户登录后,更新数据库信息,修改用户最后访问时间和登录ip,增加用户积分
public void updateLoginInfo(User user){
jdbcTemplate.update(UPDATE_LOGIN_INFO_SQL, user.getLastVisit(),
user.getLastIp(), user.getCredits(), user.getUserId());
}
}
LoginDao.java
@Repository
public class LoginLogDao {
@Autowired
private JdbcTemplate jdbcTemplate;
private final static String INSERT_LOGIN_LOG_SQL=
"INSERT INTO t_login_log(user_id, ip, login_dateteme)VALUES(?,?,?)";
//在数据库中插入用户登录的日志信息
public void insertLoginLog(LoginLog loginLog){
Object[] args = {loginLog.getUserId(), loginLog.getIp(), loginLog.getLoginDate()};
jdbcTemplate.update(INSERT_LOGIN_LOG_SQL, args);
}
}
service层
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private 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);
}
/**
* 事务增强
* @param user
*/
@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);
}
}
Controller
@Controller
public class LoginController {
@Autowired
private UserService userService;
//可以配置多个映射路径
@RequestMapping(value = {"/", "/index.html"}, method = RequestMethod.GET)
public ModelAndView loginPage(){
return new ModelAndView("login");
}
@RequestMapping(value = "/loginCheck.html", method = RequestMethod.GET)
public ModelAndView loginCheck(HttpServletRequest request, LoginCommand loginCommand){
boolean isValidUser = userService.hasMatchUser(loginCommand.getUserName(), loginCommand.getPassword());
if(!isValidUser){
return new ModelAndView("login", "error","用户名密码错误");
} else {
User user = userService.findUserByUserName(loginCommand.getUserName());
user.setLastIp(request.getLocalAddr());
user.setLastVisit(new Date());
userService.loginSuccess(user);
request.getSession().setAttribute("user", user);
return new ModelAndView("main");
}
}
jsp代码
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>xhtc</title>
</head>
<body>
<c:if test="${!empty error}">
<font color="red"><c: out value="${error}"/></font>
</c:if>
<form action='<c:url value="/loginCheck.html"/>' method="post">
用户名:
<input type="text" name="userName">
<br>
密码:
<input type="password" name="password">
<br>
<input type="submit" value="登录"/>
<input type="reset" value="重置"/>
</form>
</body>
</html>
此时的工程目录结构。
启动SpringBoot
application.java
@SpringBootApplication
//开启事务支持,可以在Service方法上标注@Transaction表示事务增强
@EnableTransactionManagement
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
protected SpringApplicationBuilder configure(SpringApplicationBuilder application){
return application.sources(Application.class);
}
/**
* 自定义事务管理方法
* 此时SpringBoot会加载自定义的事务管理器,不会重新实例化其他事务管理器
* @param dataSource
* @return
*/
@Bean
public PlatformTransactionManager txManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
"基于Spring Boot应用,由于当前应用包含了一个可直接执行的Application类,所以在开发过程中,大家很容易在IDE(如IDEA工具)中单击右键鼠标运行当前类。虽然可以启动当前应用,在非Web应用中可能不会有什么问题,单在Web应用中,如果采用上述方法直接运行应用,那么在访问有视图的页面时(如JSP),会一直报404错误。因为直接运行当前启动类,Spring Boot无法找到当前页面资源。因此,基于Spring Boot的应用在开发调试的时候,一定要基于Spring Boot提供的spring-boot-maven-plugin插件命令来运行应用或通过Spring Boot命令行来运行应用。"
—— 摘自<精通Spring 4.x ——企业应用开发实战>
所以,在web应用中,要用这样的方法去启动SpringBoot。
启动成功后,在浏览器输入 http://localhost:8080/ 即可看到登录页面。
** 部署成功!**