# springboot

# 1. 基本概念

每次创建新的SSM项目,都需要:创建Maven项目,添加依赖,配置web.xml,添加spring的配置文件,进行springmvc的相关配置,添加数据库的配置文件,配置mybatis等……准备工作相当的多,而且,随着项目的深入,可能还需要在开发过程中添加新的依赖或新的配置。

事实上,每个不同的项目,经历以上的过程是极为相似的!

使用SpringBoot可以快速的创建项目,却不用关心以上各种配置,在SpringBoot中,有一项开发理念就是“约定大于配置”,即:大多数人共同遵守的配置习惯,将在SpringBoot中成为默认配置,开发者就不必再关心这些配置了!

# 2. 基本使用

访问 http://start.spring.io

然后,确定当前需要创建的项目的参数,主要是:

顶部的项目类型、开发语言、SpringBoot版本;

  • Group,例如填写为com.springboot;
  • Artifact,例如填写为sample;
  • Name,表示项目名称,自动为Artifact的值,可以不更改;
  • Description:项目描述;
  • Package Name:项目的根包,在SpringBoot中,任何自定义组件都必须在根包或其子包中,例如控制器类、业务类等;
  • Packaging:WEB应用必须选择war;
  • Java Version:默认为8,也可以使用较低版本。

至此,项目的配置就已经完成,点击绿色的 Generate Project 按钮即可下载项目,得到项目的压缩包,将其解压,并剪切到Workspace中(这一步并不是必须的),然后在Eclipse中选择Import > Existing Maven Projects导入该项目,保证当前计算机是可以连接到Maven服务器,然后,项目会自动更新,添加所需要的所有依赖,至此,项目创建完成!

# 3. 输出Hello,SpringBoot

设计目标:当输入某请求时,服务器返回"Hello, SpringBoot!"

在项目的根包下创建子包controller,然后创建控制器类,例如HelloController,然后,添加@RestController注解:

@RestController
public class HelloController {

}

@RestController也是一种@Controller,并且,表示该控制器类中所有处理请求的方法都是@ResponseBody的。使用这个注解后,处理请求也就不可以是转发或重定向了,如果一定要转发或重定向,必须使用原有@Controller注解,并且处理请求的方法上不可以添加@ResponseBody。

然后,添加处理请求的方法:

@RestController
public class HelloController {
	
	@GetMapping("/hello.do")
	public String sayHello() {
		return "Hello, SpringBoot!";
	}

}

至此,简单的HelloWorld就已经完成!

项目的根包下有SampleApplication类(类名中Application左侧的是项目的Artifact名,所以,不同的项目,该类的名称可能不同),该类是SpringBoot项目的启动类,直接以Run as > Java Application方式启动即可,启动时,控制台会有启动日志: 在这里插入图片描述 其中,有一条:

Tomcat started on port(s): 8080 (http) with context path ''

SpringBoot是内置Tomcat的,所以,项目本身也不需要添加Tomcat运行环境,并且,SpringBoot部署项目时,如以上日志描述的,使用的Context Path是空值,以前访问时的URL可能是:

http://localhost:8080/项目名/hello.do

而在SpringBoot项目中则是:

http://localhost:8080/hello.do

也就是不需要再在URL中添加项目名了,执行效果例如:在这里插入图片描述

# 4. 关于静态资源

项目中的src\main\resources\下的static文件夹是专门用于存放静态资源的,例如图片等等: 在这里插入图片描述 然后,启动SpringBoot,在浏览器中通过http://localhost:8080/timg.jpg即可访问:在这里插入图片描述

# 5. 整合MyBatis

如果在http://start.spring.io创建项目时,并没有添加MyBatis等依赖,则需要手动添加:

<!-- 整合MyBatis -->
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>1.3.2</version>
</dependency>

然后,还需要添加数据库的驱动:

<!-- 数据库 -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>

注意:SpringBoot会自动使用最新版本的jar包,并不推荐自定义版本号,如果指定了版本,反而会提示警告: 在这里插入图片描述 然后,打开SpringBoot的配置文件src\main\resources\application.properties,添加数据库连接的相关配置:

spring.datasource.url=jdbc:mysql://localhost:3306/tedu_ums?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root

以上配置,将由SpringBoot自动读取,并注入到数据源对象中,所以,以上配置的各属性名必须是以上使用的这几个名称,不可以自行修改属性名。

开发持久层功能时,需要先创建接口,例如com.springboot.sample.mapper.UserMapper。此前使用传统的SSM开发时,需要在配置文件中指定接口所在的包,在SpringBoot中,可以为接口添加@Mapper注解,而无需添加配置。

@Mapper
public interface UserMapper {

}

在添加完抽象方法之后,传统的SSM开发中需要继续配置XML映射,但是,在SpringBoot的应用中,可以直接添加注解:

@Mapper
public interface UserMapper {

	@Select("select id, password from t_user where username=#{username}")
	User findByUsername(String username);
	
}

不难发现,当执行的任务是查询时,则添加@Select注解,与之类似的还有@Insert@Update@Delete注解,根据需要执行的任务进行选取即可!

当完成后,应该执行单元测试,可以自定义测试类,所有的测试类都应该添加注解:

@RunWith(SpringRunner.class)
@SpringBootTest
public class 测试类 ...

在编写测试方法时,所需要的对象如果是当前项目的组件,都可以自动装配:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTestCase {
	
	@Autowired
	private UserMapper userMapper;

	// ...其它

然后编写测试方法:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTestCase {
	
	@Autowired
	private UserMapper userMapper;
	
	@Test
	public void findByUsername() {
		String username = "mvc";
		User user
			= userMapper.findByUsername(username);
		System.out.println(user);
		
		username = "hello";
		user = userMapper.findByUsername(username);
		System.out.println(user);
	}

}

至此,简单的持久层访问就已经完成!

# 6. 业务层(非SpringBoot知识点)

设计业务层方法时,以操作成功(操作正确)为前提来设计返回值的类型,而几乎每个业务方法都有出错的可能,出错时,直接抛出某种异常即可!

以登录为例,方法名可以使用login,符合大多数人的英语认知;返回值应该是User,因为登录成功后,可能需要将用户的id、username等数据存入Session,则使用1个User对象可以封装这多项数据;参数应该使用String username和String password,简单易懂:

User login(String username, String password);

该方法可能出现的“错误”(指的是开发者认为用户操作失败)均通过抛出异常来表现,则调用方法时的语法可能是:

try {
	User user = userService.login("", "");
	session.setAttribute(
		"id", user.getId());
	session.setAttribute(
		"username", user.getUsername());
} catch (Username异常 e) {

} catch (Password异常 e) {

}

使用这种做法,既能满足返回正确的数据,又能体现多种不同的错误,并且,在语法上表达得也非常清楚!

抛出的异常应该继承自RuntimeException,并添加父类中已经存在的多种构造方法,便于快速创建对象!通常,异常类存放在service的子级ex包中。

由于自定义的异常都是RuntimeException的子孙类异常,Java语法并不强制要求处理这些异常,则方法的调用者可能不清楚需要处理哪些异常,所以,在方法的声明中应该明确的抛出:

public User login(
	String username, String password)
		throws UserNotFoundException, 
			PasswordNotMatchException {
	// ... 
}

并且,在方法的声明中明确的添加注释:

/**
 * 用户登录
 * @param username 用户名
 * @param password 密码
 * @return 成功登录的用户数据,包括用户的id等……
 * @throws UserNotFoundException 用户数据不存在
 * @throws PasswordNotMatchException 密码不匹配
 */
public User login(
	String username, String password)
		throws UserNotFoundException, 
			PasswordNotMatchException {
	// ... ...
}

# 7. 控制器层

先创建com.springboot.sample.controller.UserController,添加@RestController注解,然后,添加方法处理请求:

@RestController
public class UserController extends BaseController {
	
	@Autowired
	private UserService userService;

	@RequestMapping("/login.do")
	public ResponseResult login(
			String username, String password) {
		User user = userService.login(
				username, password);
		return new ResponseResult(SUCCESS);
	}
	
}

并且,另行创建控制器的基类提供静态常量,并处理异常:

public abstract class BaseController {

	protected static final int SUCCESS = 1;
	
	@ExceptionHandler(ServiceException.class)
	public ResponseResult handleException(Exception e) {
		// 判断异常的种类并进行处理
		if (e instanceof UserNotFoundException) {
			return new ResponseResult(2, e);
		} else if (e instanceof PasswordNotMatchException) {
			return new ResponseResult(3, e);
		}	
		return null;
	}
}

# 8. 插入数据时获取数据id

插入数据时,持久层的方法之前使用@Insert注解配置SQL,然后,还需要通过@Options(useGeneratedKeys=true, keyProperty="id")注解配置获取数据的id,与XML映射效果相同,插入时使用的对象在完成后将包括数据的id值。

# 9. 使用主页

src/main/resources/staticwebapp下的index.html会是默认主页,访问时,仅需通过http://localhost:8080/即可访问。

# 10. 使用错误页面

src/main/resources/resouces/error文件夹是专门用于存放错误页面的位置,默认情况下,该文件夹并不存在,需要手动创建,存放在这个文件夹下的页面文件应该使用响应码作为文件名,例如404.html,后续无须添加任何配置,只要出现错误的响应码,就会将这些页面响应到客户端。

# 11. 复习思考题

  • 为什么业务层的方法要抛出异常;

  • 关于ResponseResult类,为什么需要多种不同的构造方法;

  • 例如new ResponseResult(2, e)是什么意思;

  • 处理请求的方法为什么返回ResponseResult

  • 为什么自定义的异常需要是RuntimeException的子孙类;

  • 业务层的方法为什么需要通过throws声明抛出异常;

  • 为什么要将处理异常的代码编写在BaseController中;

  • 处理异常时,@ExceptionHandler注解中可以不配置参数吗;

Last Updated: 10/10/2021, 12:03:13 PM