spring boot 小案例
1. SpringBoot
1.1. 概要
在传统的SSM框架应用过程中,存在大量的配置文件,及相关的配置项,例如:
- 1. DispatcherServlet
- 2. CharacterEncodingFilter
- 3. <mvc:component-scan />
- 4. <mvc:annotation-driven />
- 5. <bean class="...InternalResourceViewResolver" />
- 6. <util:properties />
- 7. <bean class="...BasicDataSource" />
- 8. <bean class="...MapperScannerConfigurer" />
- 9. <bean class="...SqlSessionFactoryBean" />
这些配置在每个基于SSM框架的应用中都是需要的,每次开发时却改动很小,甚至某些配置是不需要改动的,所以,出现了SpringBoot框架!
可以把SpringBoot理解为框架的集合体,默认就添加了大量的常用依赖,并且完成了绝大部分通用的配置,从而简化了项目的创建过程。
在其它方面,SpringBoot也有很多的简化,在学习中再慢慢体会。
1.2. 使用SpringBoot
访问https://start.spring.io/
,通过该页面创建项目,主要填写必要的参数,点击Switch to the full version展开详细配置,在下方勾选所需要的jar包,然后生成项目。
下载生成的项目的压缩包,解压缩后,将项目文件夹复制或剪切到Workspace中,在Eclipse中,通过Import > Existing Maven Projects功能导入,然后等待项目更新完成(务必保证此过程中电脑是可以正常连接到Maven服务器的)。
1.3. HelloWorld
首先,SpringBoot默认并不推荐服务器端的开发任务中包含页面的开发,即服务器端依然只提供JSON数据即可,而不应该通过转发或重定向等方式处理页面(当然,功能方面还是支持的)。
由于创建项目时,Group
值为cn.tedu.boot
,Artifact
值为sample
,所以,在项目中默认存在cn.tedu.boot.sample
包,这个包也是组件扫描的包,则本项目中,所有需要被Spring管理的组件都必须在这个包或它的子孙包中!
在cn.tedu.boot.sample.controller
中创建HelloController
:
- @RestController
- @RequestMapping("/hello")
- public class HelloController {
- // 请求路径:/hello/index
- @GetMapping("/index")
- public String showIndex() {
- return "hello, spring boot.";
- }
- }
以上
@RestController
是@Controller
与@ResponseBody
的组合应用方式,当使用这个注解时,当前类中所有处理请求的方法相当于都添加了@ResponseBody
,同时,也意味着当前控制器中处理请求时不支持转发或重定向,而全部是响应正文,如果一定需要转发或重定向,只能使用@Controller
注解。
SpringBoot默认添加了许多常用的依赖,且相关的jar包都是较高的稳定版本,所以,简单的项目中可以不必自行添加依赖,如果需要添加依赖,大多数依赖是不推荐自定义版本号的。
在SpringBoot中,配置了StringHttpMessageConverter
的配置,使得响应头的ContentType
使用的字符编码是utf-8,所以,即使使用String
类型的返回值响应正文,也是支持中文的!(默认是使用的ISO-8859-1)
并且,SpringBoot默认完成了关于DispatcherServlet
的配置(事实上在SpringBoot项目中根本就不存在web.xml文件),并且映射的路径是/*
,所以,在配置映射路径时,并不要求资源名以.do
作为后缀。
在执行时,直接运行根包下的XXXApplication.java
文件中的main()
方法即可,SpringBoot中内置Tomcat,所以,在启动之前,务必保证默认端口8080
没有被占用,并且,成功启动后,在没有停止之前,不可以启动第2次,否则将导致端口冲突,第2次启动会失败!
由SpringBoot部署的项目,在URL中没有项目名称,所以,以上配置的请求,可以通过http://localhost:8080/hello/index
直接访问。
1.4. 设计注册页面
基于前后端分离的思想,页面并不需要是JSP页面,只需要是HTML页面即可。
在SpringBoot中,推荐将静态资源(HTML页面、CSS、JS、图片等)放在src/main/resources/static
目录下。
所以,在static
下创建reg.html
页,完成后,通过http://localhost:8080/reg.html
即可直接访问。
1.5. 创建实体类
- package cn.tedu.boot.sample.entity;
- import java.io.Serializable;
- public class User implements Serializable {
- private static final long serialVersionUID = 1414039275087351434L;
- private Integer id;
- private String username;
- private String password;
- private Integer age;
- private String phone;
- private String email;
- // ...
- }
1.6. 持久层
在SpringBoot项目中,使用MyBatis时,无须配置MapperScannerConfiguere
和SqlSessionFactoryBean
,可以直接开始编写代码,例如先创建cn.tedu.boot.sample.mapper.UserMapper
接口:
- public interface UserMapper {
- Integer addnew(User user);
- }
然后,在resources
下创建mappers
文件夹,并在该文件夹下添加UserMapper.xml
文件(从其它项目中复制粘贴过来):
- <mapper namespace="cn.tedu.boot.sample.mapper.UserMapper">
- <insert id="addnew">
- INSERT INTO t_user (
- username, password,
- age, phone,
- ) VALUES (
- #{username}, #{password},
- #{age}, #{phone},
- #{email}
- )
- </insert>
- </mapper>
即使不用再配置比较繁琐的内容,也不代表完全没有配置,为了保证项目能扫描得到持久层接口,需要在接口文件之前添加@Mapper
注解,同时,还需要指定持久层映射的XML文件的位置,在application.properties
文件中:
- mybatis.mapper-locations=classpath:mappers/*.xml
编码完成后,应该及时执行单元测试,以检查功能是否正常,应该在src/test/java
中的根包下创建测试类,所有测试类都应该添加@RunWith(SpringRunner.class)
和@SpringBootTest
注解,相当于加载Spring配置文件以获取Spring容器,甚至完成其它的初始化配置,然后,所需要的Bean可以直接声明并添加@Autowired
通过自动装配来得到值,接下来,编写测试方法即可:
- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class UserMapperTestCase {
- @Autowired
- UserMapper userMapper;
- @Test
- public void addnew() {
- User user = new User();
- user.setUsername("boot");
- user.setPassword("8888");
- Integer rows = userMapper.addnew(user);
- System.err.println("rows=" + rows);
- }
- }
通常,注册功能中,要求“用户名必须是唯一的”,所以,为了保证注册功能的完整性,还应该提供“根据用户名查询用户数据是否存在”的查询功能!对应的抽象方法可以是:
- User findByUsername(String username);
匹配的映射是:
- <select id="findByUsername"
- resultType="cn.tedu.boot.sample.entity.User">
- SELECT
- id
- FROM
- t_user
- WHERE
- username=#{username}
- </select>
注意:由于这个查询功能应用于“注册时检查用户名是否被占用”,所以,并不关心查询到的数据的各属性值是多少,那么,在查询时,应该只查询必要的字段,如果所有字段都不关心,则只选取其中任一字段即可。
功能完成后,还是应该及时的编写测试:
- @Test
- public void findByUsername() {
- String username = "boot";
- User user
- = userMapper.findByUsername(username);
- System.err.println(user);
- }
- public void deGet() {
- // 接收用户提交的用户名等参数
- // Dao > 检查用户名是否被占用
- // 是:被占用 > 提示错误
- // 否:没有被占用 > Dao > 插入数据
- // -- 提示成功
- }
1.7. 业务层
通常,业务层应该由业务接口和业务实现类来共同组成,例如创建cn.tedu.boot.sample.service.IUserService
- package cn.tedu.boot.sample.service;
- public interface IUserService {
- }
然后,创建cn.tedu.boot.sample.service.impl.UserServiceImpl
类实现该接口:
- package cn.tedu.boot.sample.service.impl;
- import cn.tedu.boot.sample.service.IUserService;
- public class UserServiceImpl
- implements IUserService {
- }
接下来,应该在接口中声明抽象方法,该方法表示向外提供的功能,例如注册、登录、修改密码等,此次需要完成的是注册,则:
- void reg(User user); // throws 用户名被占用异常, XX异常;
注意:设计抽象方法时,仅以“成功”为前提来考虑方法的返回值类型!如果失败,使用抛出异常的方式来表现。
- try {
- } catch (用户名被占用异常 e) {
- } catch (XXX异常 e) {
- }
然后,在实现类中,声明持久层对象private UserMapper userMapper;
并添加@Autowired
注解,当前类也应该添加@Service
注解,然后,实现以上方法:
- @Service
- public class UserServiceImpl
- implements IUserService {
- @Autowired
- private UserMapper userMapper;
- @Override
- public void reg(User user) {
- // 根据user.getUsername()查询数据
- String username = user.getUsername();
- User data = userMapper.findByUsername(username);
- // 判断数据是否为null
- if (data == null) {
- // 是:为null,即:用户名未被使用,则插入数据
- userMapper.addnew(user);
- } else {
- // 否:非null,即:用户名被占用,则抛出异常
- throw new RuntimeException(
- "注册失败!您尝试注册的用户名(" + username + ")已经被占用!");
- }
- }
- }
最后,执行单元测试:
- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class UserServiceTestCase {
- @Autowired
- IUserService userService;
- @Test
- public void reg() {
- try {
- User user = new User();
- user.setUsername("service");
- user.setPassword("8866");
- userService.reg(user);
- System.err.println("注册成功!");
- } catch (RuntimeException e) {
- System.err.println(e.getMessage());
- }
- }
- }
1.8. 控制器层
先创建控制器类cn.tedu.boot.sample.controller.UserController
,添加@RestController
和@RequestMapping("/user")
:
- @RestController
- @RequestMapping("/user")
- public class UserController {
- }
控制器类本身并不完成实际功能的处理,主要作用是接收请求、给予响应结果,所以,在功能的处理方面,它会依赖于业务层private IUserService userService;
并通过@Autowired
注入值:
- @Autowired
- private IUserService userService;
接下来,应该设计所需要处理的请求,此次的请求是用户将提交注册相关数据,尝试执行注册,所以,请求的类型应该是POST
,请求的参数应该是包括注册的所有数据,例如用户名、密码、年龄等,在SpringMVC中,可以使用User
对象接收这些参数,在响应时,仍推荐使用JSON数据进行响应,所以,应该提前创建好ResponseResult
类,作用处理请求的方法的返回值:
- package cn.tedu.boot.sample.util;
- import java.io.Serializable;
- public class ResponseResult<T> implements Serializable {
- private static final long serialVersionUID = -5015220243507112803L;
- private Integer state;
- private String message;
- private T data;
- // SET/GET
- }
然后,在控制器类中添加处理请求的方法:
- @RequestMapping("/reg")
- public ResponseResult<Void> handleReg(User user) {
- }
最原始的处理方式为:
- @RequestMapping("/reg")
- public ResponseResult<Void> handleReg(User user) {
- ResponseResult<Void> rr = new ResponseResult<Void>();
- try {
- userService.reg(user);
- rr.setState(1);
- rr.setMessage("注册成功");
- return rr;
- } catch (RuntimeException e) {
- rr.setState(2);
- rr.setMessage(e.getMessage);
- return rr;
- }
- }
为了快速的创建ResponseResult
并确定state
和message
属性的值,简化以上代码,所以,可以在ResponseResult
类中添加新的构造方法:
- public ResponseResult(Integer state, String message) {
- super();
- this.state = state;
- this.message = message;
- }
- public ResponseResult(Integer state, Exception e) {
- super();
- this.state = state;
- this.message = e.getMessage();
- }
所以,原有的控制器中的代码可以调整为:
- @RequestMapping("/reg")
- public ResponseResult<Void> handleReg(User user) {
- try {
- userService.reg(user);
- return new ResponseResult<Void>(1, "注册成功");
- } catch (RuntimeException e) {
- return new ResponseResult<Void>(2, e);
- }
- }
为了便于统一处理异常,应该添加专门的方法进行处理:
- @ExceptionHandler(RuntimeException.class)
- public ResponseResult<Void>
- handleException(Exception e) {
- return new ResponseResult<>(2, e);
- }
则控制器中不必再处理异常:
- @RequestMapping("/reg")
- public ResponseResult<Void> handleReg(User user) {
- // 执行注册
- userService.reg(user);
- // 注册成功,确定返回值
- return new ResponseResult<>(1, "注册成功!");
- }
全部完成后,可以在浏览器的地址栏中输入http://localhost:8080/user/reg?username=exception&password=666
进行测试(如果有更多非空字段的设计,请添加更多参数),测试完成后,将以上处理请求的方法的注解修改为@PostMapping
。
spring boot 小案例的更多相关文章
- (转)Spring Boot (十三): Spring Boot 小技巧
http://www.ityouknow.com/springboot/2017/06/22/spring-boot-tips.html 一些 Spring Boot 小技巧.小知识点 初始化数据 我 ...
- Spring Boot(十三):spring boot小技巧
Spring Boot(十三):spring boot小技巧 一.初始化数据 我们在做测试的时候经常需要初始化导入一些数据,如何来处理呢?会有两种选择,一种是使用Jpa,另外一种是Spring JDB ...
- Spring Boot (十三): Spring Boot 小技巧
一些 Spring Boot 小技巧.小知识点 初始化数据 我们在做测试的时候经常需要初始化导入一些数据,如何来处理呢?会有两种选择,一种是使用 Jpa,另外一种是 Spring JDBC .两种方式 ...
- 最近做的一个Spring Boot小项目,欢迎大家访问 http://39.97.115.152/
最近做的一个Spring Boot小项目,欢迎大家访问 http://39.97.115.152/,帮忙找找bug,网站里有源码地址 网站说明 甲壳虫社区(Beetle Community) 一个开源 ...
- 【微框架】之一:从零开始,轻松搞定SpringCloud微框架系列--开山篇(spring boot 小demo)
Spring顶级框架有众多,那么接下的篇幅,我将重点讲解SpringCloud微框架的实现 Spring 顶级项目,包含众多,我们重点学习一下,SpringCloud项目以及SpringBoot项目 ...
- Spring Boot 小技巧
初始化数据 我们在做测试的时候经常需要初始化导入一些数据,如何来处理呢?会有两种选择,一种是使用 Jpa,另外一种是 Spring JDBC .两种方式各有区别下面来详细介绍. 使用 Jpa 在使用s ...
- Spring Boot 入门案例与配置说明
一.Spring Boot简介 官网地址:http://spring.io/projects/spring-boot Spring Boot可以轻松创建可以运行的独立的,生产级的基于Spring的应用 ...
- 【微框架】之一:从零开始,轻松搞定SpringCloud微服务系列--开山篇(spring boot 小demo)
Spring顶级框架有众多,那么接下的篇幅,我将重点讲解SpringCloud微框架的实现 Spring 顶级项目,包含众多,我们重点学习一下,SpringCloud项目以及SpringBoot项目 ...
- spring boot 整合案例
github : https://github.com/nbfujx/springBoot-learn-demo
随机推荐
- 从零开始的全栈工程师——利用CSS3画一个正方体 ( css3 )
transform属性 CSS3的变形(transform)属性让元素在一个坐标系统中变形.transform属性的基本语法如下: transform:none | <transform-fun ...
- 集合的前N个元素
集合的前N个元素:编一个程序,按递增次序生成集合M的最小的N个数,M的定义如下: (1)数1属于M: (2)如果X属于M,则Y=2*x+1和Z=3*x+1也属于M: (3)此外 ...
- CSS垂直居中的四种方法
写在前面的话 最近在Stack Overflow上看到 一个不错的回答 ,以下是我对其的总结,分享给大家. 垂直居中的四种方法 ①基础的方法 设置父元素的line-height等于height,这种方 ...
- drupal 基础理论
第3章 Drupal 的基本概念 添加新评论 浏览 6795 次 Drupal的基本概念主要包括节点.内容类型.模块.主题和分类等.只有对这些概念有了足够的了解,方能灵活的构建网站.本章将对这些基本概 ...
- 前端小课堂 js:what is the function?
js 函数: 概念:函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块. 说白了就是响应用户操作所执行的代码,通过js事件触发,然后调用执行函数里代码的操作. 比如常见的用户点击事件,用户点击 ...
- 使用HTML5 canvas做地图(2)瓦片以及如何计算的
上一篇也说到瓦片,我们为什么使用瓦片?这一篇主要是关于如何拼接地图? 下面的一张图,可以一眼明了,地图是如何切割以及拼接的. 瓦片信息 瓦片信息包括切图原点,瓦片大小,格式,分辨率以及分辨率级别等. ...
- 详解Struts1.x的运行机制及命名规则
Struts1.x 调用一个action的大致流程: 1)首先前端发送 *.do的一个action请求(通过点击表单提交按钮,js 事件等): 2)web.xml 文件通过 *.do 找到 Actio ...
- xml linq
这里讲解一下linq对xml的基本操作,包括: 新建xml.新建节点 查询节点 插入属性.插入节点 替换节点 在这里我封装了一些常用的方法: public class XmlHelper { /// ...
- 基于alpine定制常用命令镜像
FROM alpine RUN apk update RUN apk add curl coreutils 像busybox.alpine镜像date命令都不是完整版的,不能执行加减的操作(date ...
- day3 函数、递归、及内置函数
请查看我的云笔记链接: http://note.youdao.com/noteshare?id=7d5aa803981ae4375a1f648f48e7ade3&sub=5DFD553A6C5 ...