目录
引言
最近需要完成一个管理系统后端的开发,大二暑期实训期间学了后端框架,包括springBoot、mybatis、spring、springMVC等。但是学时很短,仅仅是对老师的笔记中的简单示例进行了测试,对后端中Dao层、Service层、Controller层的理解不够深刻,这次通过实际项目对之前所学的后端知识进行巩固与提高,下面是对后端各个框架的基础的复习,可能有不太恰当的地方,如果某些内容与你的问题相符,但刚好我没说清楚,请留言,我将尽力为你解决,共同学习。
技术栈
spring boot:专注于spring开发减少配置
mybatis:持久层的、轻量级的半自动化ORM框架
springMVC:基于JAVA实现MVC的轻量级Web框架。
知识点
接口
在JAVA中接口是一个公共的抽象类,只有方法的特征没有方法的实现。可以由多个类来实现它,并且这些实现可以具有不同的行为。为JAVA无法实现多继承提供一种解决手段。一个接口可以在多个地方实现
Static类
static表示静态或者全局的意思,被static修饰的可以是一个变量、一个类或者一段代码块,在java中没有全局变量的说法,被static修饰的成员变量或者成员方法独立于该类的任何对象,它不依赖于类的特定实例,被所有实例所共享,当一个类被创建时,便能够访问到它。
实现
Spring
一个轻量级的控制反转与面向切面编程的框架。
尝试传统实现一个简单功能的方式,在Dao层创建一个功能实现的接口,再创建一个该接口的实现类,而后在Service层创建一个接口并创建它的实现类。需要使用时,需要实例化Service层的实现类,当需要执行另外一个操作时马上又需要实例化另外一个实现类,这样的方式非常繁琐。
// userDao的实现类
package dao.Impl;
import dao.userDao;
public class userDaoImpl implements userDao{
@Override
public void getUser() {
System.out.println("取得用户");
}
}
// userDao的接口
package dao;
public interface userDao {
public void getUser();
}
// userService的实现类
package service.Impl;
import dao.Impl.userDaoImpl;
import dao.userDao;
import service.userService;
public class userServiceImpl implements userService {
private userDao userDao = new userDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
// userService的接口
package service;
public interface userService {
public void getUser();
}
如果我们尝试在Service的实现类中留出一个接口,而不是具体地实现某个功能,便能带来较大的便捷。
// 在service实现类中设置一个接口
package service.Impl;
import dao.Impl.userDaoImpl;
import dao.userDao;
import service.userService;
public class userServiceImpl implements userService {
// 该方式过度的耦合,使用set方式流出一个接口
// private userDao userDao = new userDaoImpl();
private userDao userDao;
public void setUserDao(userDao userDao){
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
// 当需要使用到某个功能的时候,直接将Dao层的实现类传入之前留出的接口
import dao.Impl.userDaoImpl;
import dao.Impl.userDaoMysqlImpl;
import service.Impl.userServiceImpl;
import service.userService;
public class Test {
@org.junit.Test
public void test(){
// 先执行userDaoMysqlImpl
userServiceImpl userService = new userServiceImpl();
userService.setUserDao(new userDaoMysqlImpl());
userService.getUser();
// 此时又想执行另外一个功能
userService.setUserDao(new userDaoImpl());
userService.getUser();
}
}
通过set注入的方式,有效地解决了当使用数据层不同的功能时在Service层需要new不同的数据层的实现类,但是目前仍然存在只要使用数据层就要在服务层new一个实现类,当数据层改变时服务层也需要跟着改变,便调整由service主动new数据层的实现类为由外部提供Service层的需要,这便是控制反转(IOC)的思想。控制反转通过一个bean容器创建和初始化Dao层与Service层的类对象,虽然容器中有了Dao层与Service层的类对象,但是程序还不能执行,因为Service层提供服务需要依赖于Dao层,所以在bean容器中需要将Service层与Dao层建立依赖关系,这便是依赖注入(DI)。
// 添加spring依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
// 编写beans.xml文件
<bean id="hello" class="pojo.Hello" >
<property name="name" value="spring"/>
</bean>
// 测试
@org.junit.Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
hello.show();
}
我们再将控制反转与依赖注入同时运用起来
<!-- 依赖注入 -->
<bean id="userDao" class="dao.Impl.userDaoImpl"/>
<!-- 将userDaoService与userDao绑定 -->
<bean id="userDaoService" class="service.Impl.userServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
// userServiceImpl通过set留出功能实现的接口
package service.Impl;
import dao.Impl.userDaoImpl;
import dao.userDao;
import service.userService;
public class userServiceImpl implements userService {
// 该方式过度的耦合,使用set方式流出一个接口
// private userDao userDao = new userDaoImpl();
private userDao userDao;
public void setUserDao(userDao userDao){
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
// 测试
@org.junit.Test
public void test3(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
userServiceImpl userService = (userServiceImpl)context.getBean("userDaoService");
userService.getUser();
}
MyBatis
mybatis针对持久层的一个框架,回忆一下,传统操作数据的方式大概如下,配置连接数据库、使用sql语句执行具体的操作、封装结果使用对象承接,这些操作都需要自己手动完成。而mybatis能够大大简化这些操作,通过下面两幅图片对边便能感觉到mybatis的方便。
编写实体类
public class User {
private long id;
private String username;
private String password;
private String name;
private String phone;
private String head_url;
private long dept_id;
private long post_id;
private String description;
private int status;
private Date create_time;
private Date update_time;
private int is_deleted;
public User (){
}
public User(long id, String username, String password, String name, String phone, String head_url, long dept_id, long post_id, String description, int status, Date create_time, Date update_time, int is_deleted) {
this.id = id;
this.username = username;
this.password = password;
this.name = name;
this.phone = phone;
this.head_url = head_url;
this.dept_id = dept_id;
this.post_id = post_id;
this.description = description;
this.status = status;
this.create_time = create_time;
this.update_time = update_time;
this.is_deleted = is_deleted;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getHead_url() {
return head_url;
}
public void setHead_url(String head_url) {
this.head_url = head_url;
}
public long getDept_id() {
return dept_id;
}
public void setDept_id(long dept_id) {
this.dept_id = dept_id;
}
public long getPost_id() {
return post_id;
}
public void setPost_id(long post_id) {
this.post_id = post_id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public Date getCreate_time() {
return create_time;
}
public void setCreate_time(Date create_time) {
this.create_time = create_time;
}
public Date getUpdate_time() {
return update_time;
}
public void setUpdate_time(Date update_time) {
this.update_time = update_time;
}
public int getIs_deleted() {
return is_deleted;
}
public void setIs_deleted(int is_deleted) {
this.is_deleted = is_deleted;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", phone='" + phone + '\'' +
", head_url='" + head_url + '\'' +
", dept_id=" + dept_id +
", post_id=" + post_id +
", description='" + description + '\'' +
", status=" + status +
", create_time=" + create_time +
", update_time=" + update_time +
", is_deleted=" + is_deleted +
'}';
}
}
编写Dao接口
public interface userDao {
List<User> getUserList();
}
编写mapper具体实现
<mapper namespace="dao.userDao">
<select id="getUserList" resultType="pojo.User">
select * from user;
</select>
</mapper>
在mybatis-config.xml核心配置文件中注册
<mappers>
<mapper resource="dao/mapper/userDaoMapper.xml"></mapper>
</mappers>
创建一个sqlSessionFacrory工具类
public class MybatisUtils {
// 定义一个工厂
private static SqlSessionFactory sqlSessionFactory;
static {
try {
// 使用mybatis获取sqlsessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
测试
public void test4(){
// 获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 执行sql
userDao mapper = sqlSession.getMapper(userDao.class);
List<User> userList = mapper.getUserList();
userList.forEach(System.out::println);
// 关闭sqlSession
sqlSession.clearCache();
}
SpringMVC
使用内置的tomcat无法启动,后面再解决
SpringBoot
springboot只需要极少量的配置,便能够运行起来一个web程序。
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
主启动
@SpringBootApplication
public class SpringBoot01Application {
public static void main(String[] args) {
SpringApplication.run(SpringBoot01Application.class, args);
}
}
控制类
@RestController // @Controller + @ResponseBody
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/h1")
public String hello(){
return "Hello~ SpringBoor,你用起来真的太香了";
}
}
问题
1. idea连接阿里云mysql数据库,使用idea自动下载数据库连接驱动,下载不下来,主机使用了代理,但是idea没有设置,所以还是会很慢,使用auto detect proxy 解决了。猜测使用该设置后idea会自动寻找主机的代理。
2. idea使用kotlin,交付过来的后端代码idea的版本是23版本的,默认的kotlin为1.9x版本,在maven中也是设置也是1.9。我的idea是21版本,最高支持1.6版本,尝试将maven中的关于kotlin的版本的配置降低,发现并不管用,显示mybatis中有依赖与1.9版本的kotlin,于是尝试安装idea23版本,再次装在maven配置。可能也是需要配置idea代理,虽然在maven中设施了使用阿里云的maven仓库,但是还是速度很慢,挂了2小时后终于下载完成了。
3. 配置mybatis出现:
(1)org.apache.ibatis.binding.BindingException: Type interface dao.userDao is not known to the MapperRegistry.
出现这种问题大概是因为没有在mybatis-config.xml中注册userDaoMapper.xml
(2)Caused by: java.io.IOException: Could not find resource com/lxyk/dao/UserMapper.xml,这个报错很可能有两种原因,一个是设置的Pojo类或者Dao类的路径不对,还有一种原因就是没有在pom.xml中加入下面的这段代码。
<!--在build中配置resources 来防止我们资源导出失败的问题-->
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
4. 使用Spring Boot启动最简单的web,配置好了启动类以及需要访问的控制类,但是一直出现Whitelabel Error Page,查阅资料发现是启动类与控制类不在同一个包下,如果不使用@ComponentScan就会出现启动类找不到控制类的情况。下面呈现正确的组织方式,两个类需要在同一个主包下面。
也可以在启动类使用@ComponentScan("控制类的路径")