MVC
MVC 设计模型(设计思想)
说明:在大型项目中由于模块众多,如果将所有项目都写到一起则代码特别混乱,不便于后期维护,所以通过MVC设计模型(设计思想),将代码进行分级,利于解耦
实现步骤:一般分3层,也可以分4层,5层,每层利用接口实现统一管理调用
- M(Model) 持久层 代码与数据库进行交互的代码 Mybatis dao层,还可加多Cao层
- C(Controller)控制层 完成某项业务的具体操作过程 Controller层 & Service层
- V (View)视图层 一般指用户看到的内容(页面)
Spring容器管理3层代码结构
- 定义User POJO对象
package ink.pingdu.pojo;
public class User { //通过容器使用set方法为对象的属性赋值,所以必须有set方法
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
- 在定义好的包dao下定义dao接口/实现类(说明:Spring内部)
Mybatis就是面向接口开发,所以在操作持久层时就写接口例:UserDao
UserDao接口
package ink.pingdu.dao;
import ink.pingdu.pojo.User;
public interface UserDao {
/*要求调用者传一个User过来,从而实现add user.
不过只有接口是无法干活的(无法add),所以必须要有实现类*/
void addUser(User user);
}
UserDaoImpl 实现类
package ink.pingdu.dao;
import ink.pingdu.pojo.User;
public class UserDaoImpl implements UserDao{
//实现接口方法
@Override
public void addUser(User user) {
//下面为伪代码,实现开发中是需要链接数据库并执行SQL
System.out.println("链接数据库执行 insert into:"+user);
}
}
- 在定义好的service包下定义Service接口/实现类
UserService 接口
package ink.pingdu.service;
import ink.pingdu.pojo.User;
public interface UserService {
void addUser(User user);
}
UserServiceImpl 实现类
package ink.pingdu.service;
import ink.pingdu.dao.UserDao;
import ink.pingdu.dao.UserDaoImpl;
import ink.pingdu.pojo.User;
public class UserServiceImpl implements UserService{
//三层代码总之是有关联才能贯通,需要调用持久层的东西,所以需要调用Dao层
// private UserDao userDao = new UserDaoImpl();//早期只能new它的实现类来调用它的方法
private UserDao userDao; //基于Spring注入Dao 面向接口编程,写的是接口,实现注入的是实现类
//Spring中通过DI(依赖注入):使用Set方法为属性赋值
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser(User user) { //别人传给UserServiceImpl的user要传给userDao
//加工就是Service层的必要性,例:
String name = user.getName()+"加工数据"; // name就是加工后的数据
user.setName(name); //存入加工后的数据
userDao.addUser(user); //接收UserServiceImpl的加工后的user,并入库操作
}
}
- 在Controller包下定义UserController
package ink.pingdu.controller;
import ink.pingdu.pojo.User;
import ink.pingdu.service.UserService;
/**
* 实现类,不写成接口的原因:
* controller为顶层的,不需要被别的类调用,都是自己调用自己,
* 不需要写成接口,因为接口是为了被别人类调用。
*/
public class UserController {
/*controller层不可能单独实现读写数据库,所以需要根据结构化的层
级代码调用service层
*/
private UserService userService; //Spring容器负责注入service对象
private User user; //暂代替用户传入的数据,本来是由前端传入
//IOC 通过Set注入对象
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setUser(User user) {
this.user = user;
}
public void addUser(){
userService.addUser(user); //传入的 user,Spring注入的(见属性)
}
}
- 编辑xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1、构建user对象,POJO对象是用来封装业务属性的,该对象通过Di注入要传给Controller,然后一直传到DAO层并写入数据库-->
<bean id="user" class="ink.pingdu.pojo.User">
<property name="id" value="100"></property>
<property name="name" value="springMVC设计模式"></property>
</bean>
<!--2、构建Dao对象(与User对象不能有关系,本对象没有话语权,数据是由service传过来,所以上层还得构建Service与自己关联)
根据面向接口编程书写规范:Id 必须写接口的名称 class 必须写实现类的包路径-->
<bean id="userDao" class="ink.pingdu.dao.UserDaoImpl"></bean>
<!--3、构建Service(要把数据传递给Dao,所以在Service中需要Dao对象,所以Spring会通过Set方法给Service注入Dao对象)
书写规范同Dao
但是要注意:因为Service要与Dao有关联所以Service就会有一个Dao,做为Service的属性,有属性就得为它赋值
因为赋的不是一个具体的值,而是要赋予的是一个UserDao对象,所以不用Value,而是用ref(引用)-->
<bean id="useService" class="ink.pingdu.service.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<!--4、构建Controller(User对象本来是由前端传入,但是本次测试我们自己给User赋值,User对象注入给Controller后
把数据传下去,一直传到Dao层,写入数据库。)
注意:编写规范一样。另该类有两个属性需要注入
-->
<bean id="userController" class="ink.pingdu.controller.UserController">
<property name="userService" ref="useService"></property>
<property name="user" ref="user"></property>
</bean>
</beans>
- 编辑测试类
package ink.pingdu;
import ink.pingdu.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void testSpringMVC(){
ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
//注意:调程序,从Controller开始
UserController userController = (UserController) context.getBean("userController");
userController.addUser();
System.out.println("恭喜学会MVC结构");
}
}
补充:
三层代码结构关联 (目的:为了松耦合)
**MVC**
* Controller:为了接收用户提交的参数
* Service: 为了对数据进行业务处理(数据处理后是在内存中,线程执行完后内存资源就释放了,数据就会丢失。
* Dao (官方叫: Mapper):为了对数据进行持久化操作
Controller想addUser ,所以Service也为它准备了addUser,此时Controller与Service根本没有关联,那Controller想调用Service的addUser方法,就必须把UserService对象传给Controller,此时如果是new Service那就不是松耦合了,所以Spring通过DI(set方法注入),获得了userService对象,那自然可以用它的方法 service.addUser(),Service中间层做业务处理完后要想把数据入库,需要Dao层帮助,因为是同一个业务,所以Dao也为Service准备了addUser方法,Service要想调用Dao的方法,所以Service层也得注入Dao对象(userDao),获取到UserDao,也就可以调用其方法addUser,程序运行到Dao层,Dao运行其内部的addUser()实现数据写入数据库。<注意:调用接口时,其实现类必然会执行>
图示:红箭头为程序运行顺序
补充说明:
如果从Controller --> Service --> Dao/Mapper 叫自上而下的开发方式,如果是从 Dao/Mapper --> Service --> Controller 叫自下而上的开发方式,初学阶段建议自下而上的方式开发,这样有利于理解。
关于特殊字符说明
原因:
由于业务需要xml配置文件中可能会有特殊字符,但是该特殊字符与xml关键字(标签)形成冲突。
解决方案:
实现字符串转义:
<!--构建user对象,要显示为 <范冰冰> 冲突示范:-->
<bean id="user" class="ink.pingdu.pojo.User">
<property name="id" value="100"></property>
<property name="name" value="<范冰冰>"></property>
</bean>
<!--正确示范一:
特殊转义字符:
< < 小于
> > 大于
& & 和号
' ' 单引号
" " 引号-->
<bean id="user" class="ink.pingdu.pojo.User">
<property name="id" value="100"></property>
<property name="name" value="<范冰冰>"></property>
</bean>
<!--正确示范二:
万能转义字符:<![CDATA[...任意字符]]>-->
<bean id="user" class="ink.pingdu.pojo.User">
<property name="id" value="100"></property>
<property name="name">
<value><![CDATA[<范冰冰>]]></value>
</property>
</bean>