SpringBoot实践

开始折腾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/ 即可看到登录页面。

** 部署成功!**

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容