基本的步骤就不说了,反正前面这么多案例了已经
现在,就把maven坐标与创建好的目录看一下
名字 | 实例名/插件名 |
---|---|
springmvc框架 | spring-webmvc |
spring操纵jdbc | spring-jdbc |
spring操纵test测试 | spring-test |
mybatis框架 | mybatis |
servlet技术(运行需要屏蔽,即provided) | javax.servlet-api |
json技术 | jackson-databind |
德鲁伊数据库连接池 | druid |
mybatis整合spring | mybatis-spring |
junit测试 | junit |
mysql驱动 | mysql-connector-java |
tomcat7插件(需要配端口与路径) | tomcat7-maven-plugin |
这里必须将characterEncoding=UTF-8
放在url参数第一位!
jdbc.properties
jdbc.classname=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/20220806lige?characterEncoding=UTF-8&useSSL=false&useServerPrepStmts=true&useUnicode=true
jdbc.username=root
jdbc.password=root
SpringConfig.java
配置类
JdbcConfig.java
配置类
package cn.calendo.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
public class JdbcConfig {
//把jdbc.properties里的变量引入(通过@Value注解形式)
@Value("${jdbc.classname}")
private String classname;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
//收集连接池数据,整理成一个bean交给Spring管理
@Bean
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(classname);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
//事务控制器,整理成一个bean交给Spring管理
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
DataSourceTransactionManager ds = new DataSourceTransactionManager();
ds.setDataSource(dataSource);
return ds;
}
}
MybatisConfig.java
配置类
public class MybatisConfig {
//开始造mybatis最渴望需要的工厂bean(又需要我们提供已造好的datasource),并启用类型别名(需要扫描pojo包)
//这个datasource是在spring容器中自动帮我们装配好的(对,就是前面我们JdbcConfig设置好的datasource提交给spring容器处理好的)
//返回一个工厂bean交给spring容器处理
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setTypeAliasesPackage("cn.calendo.pojo");
return sqlSessionFactoryBean;
}
//这个bean来指定从pojo类字段到dao层接口的映射,由于我们在dao中配的是接口,所以我们写到dao包即可
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("cn.calendo.dao");
return msc;
}
}
ServletConfig.java
配置类
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
//对于root,我们需要加载spring的核心配置类,当web容器启动时,getRootConfigClasses会加载SpringConfig里面的bean
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
//由于SpringMVC是Spring的父容器,所以SpringMVC容器能访问Spring容器中的东西,而Spring容器不能访问SpringMVC容器中的东西
@Override
//对于web容器,我们需要加载springMvc的配置类,当web容器启动时,getServletConfigClasses会加载SpringMVCConfig里面的bean
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMVCConfig.class};
}
@Override
//springmvc需要拦截所有请求给自己处理,而不是给servlet一点机会
protected String[] getServletMappings() {
return new String[]{"/"};
}
//这里本来可以写过滤器,但是我们先不写吧
}
SpringMVCConfig.java
配置类
@Configuration
//他需要读取controller层的方法进行配置
@ComponentScan({"cn.calendo.controller"})
//必定开启功能强大的注解
@EnableWebMvc
public class SpringMVCConfig {
}
sql脚本:
use 20220806lige;
drop table if exists tb_user;
create table tb_user
(
id int primary key auto_increment,
username varchar(20),
password varchar(20),
gender varchar(8),
address text
);
INSERT INTO tb_user
VALUES (1, '张三', '123456', '男', '浙江,杭州');
INSERT INTO tb_user
VALUES (2, '李四', '123456', '女', '浙江,温州');
INSERT INTO tb_user
VALUES (3, '王五', '123456', '男', '江苏,苏州');
INSERT INTO tb_user
VALUES (4, '刘六', '123456', '女', '江苏,南京');
INSERT INTO tb_user
VALUES (5, '孙七', '123456', '男', '山东,青岛');
INSERT INTO tb_user
VALUES (6, '钱吧', '123456', '女', '山东,烟台');
INSERT INTO tb_user
VALUES (7, '阿猫', '123456haode', '无', '福建,厦门');
INSERT INTO tb_user
VALUES (8, '阿狗', '1234we56', '无', '广东,深圳');
INSERT INTO tb_user
VALUES (9, '阿信', 'hahaha123456', '女', '广东,广州');
INSERT INTO tb_user
VALUES (10, '阿文', 'wokao123456', '男', '上海');
好的现在表已经建好了
pojo
实体类
public class User {
private Integer id;
private String username;
private String password;
private String gender;
private String address;
public Integer getId() {
return id;
}
public void setId(Integer 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 getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
//toString其实只是给我们调试用,其它没啥用的,但是我们都会加上它的
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", gender='" + gender + '\'' +
", address='" + address + '\'' +
'}';
}
}
public interface UserDao {
//md我们很懒我们写了接口然后不想自己写实现类,那就用mybatis的代理来帮我们创建这些实现类啊
@Insert("insert into tb_user values(null, #{username}, #{password}, #{gender}, #{address})")
public void add(User user);
@Update("update tb_user set username = #{username}, password = #{password}, gender = #{gender}, address = #{address} where id = #{id}")
public void update(User user);
@Delete("delete from tb_user where id = #{id}")
public void delete(Integer id);
@Select("select * from tb_user where id = #{id}")
public User selectById(Integer id);
@Select("select * from tb_user")
public List<User> selectAll();
}
UserService
实现类
public interface UserService {
/**
* 新增/保存
* @param user
* @return
*/
public boolean addUser(User user);
/**
* 修改/更新
* @param user
* @return
*/
public boolean updateUser(User user);
/**
* 删除/注销
* @param user
* @return
*/
public boolean deleteUser(User user);
/**
* 单个查询
* @param id
* @return
*/
public User selectUserById(Integer id);
/**
* 查询所有
* @return
*/
public List<User> selectAllUser();
}
UserServiceImpl
实现类
//定义组件给SpringConfig扫描到
@Service
public class UserServiceImpl implements UserService {
//由于自动装配了我们就没有new一个user对象,idea好心帮我们查了,但是这不是错误,把这个错误忽略即可
//自动装配,不需要我们手动实例化
@Autowired
private UserDao userDao;
//然后我们需要调用Dao层的接口,把值传进去
public boolean addUser(User user) {
userDao.add(user);
return true;
}
public boolean updateUser(User user) {
userDao.update(user);
return true;
}
public boolean deleteUser(Integer id) {
userDao.delete(id);
return true;
}
public User selectUserById(Integer id) {
return userDao.selectById(id);
}
public List<User> selectAllUser() {
return userDao.selectAll();
}
}
UserController
//设置组件名,给springmvc加载,以及虚拟路径
@RestController
@RequestMapping("/users")
public class UserController {
//也是自动装配,调用service层
@Autowired
private UserService userService;
//post请求,参数实体类,用json传数据
@PostMapping
public boolean addUser(@RequestBody User user) {
return userService.addUser(user);
}
//put请求,参数实体类,用json传数据
@PutMapping
public boolean updateUser(@RequestBody User user) {
return userService.updateUser(user);
}
//delete请求,参数id,用路径传递
@DeleteMapping("/{id}")
public boolean deleteUser(@PathVariable Integer id) {
return userService.deleteUser(id);
}
//get请求,参数id,用路径传递
@GetMapping("/{id}")
public User selectUserById(@PathVariable Integer id) {
return userService.selectUserById(id);
}
//get请求,无参数
@GetMapping
public List<User> selectAllUser() {
return userService.selectAllUser();
}
}
在企业开发中,当我们写完业务层service
接口时需要进行junit测试
,以及写完表现层controller
接口时需要进行api-post
测试
service
测试//spring调用junit需要的引用类
//指定配置类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class UserServiceTest {
@Autowired
private UserService userService;
/**
* 测试删除一个用户
* @param id
*/
@Test
public void testDeleteUser(Integer id){
boolean user = userService.deleteUser(2);
System.out.println(user);
}
/**
* 测试根据id选择用户
* @param id
*/
@Test
public void testSelectUserById() {
User user = userService.selectUserById(1);
//正规测试需要做断言匹配
System.out.println(user);
}
/**
* 测试选择全部用户
*/
@Test
public void testSelectAllUser() {
List<User> ListUser = userService.selectAllUser();
System.out.println(ListUser);
}
}
controller
测试建立测试数据(delete不需要任何数据只要在url上添加数字即可(遵循rest风格))
如果数据库中文是问号?
那就在jdbc.properties后面加参数,示例:
jdbc.url=jdbc:mysql://localhost:3306/20220806lige?characterEncoding=UTF-8
成功
这就是前端与后端人员之间的通信协议
code代表操作的方法,以及成功与否1
成功0
失败
成功,数据都在data
里,失败,返回信息放在msg
里
package cn.calendo.controller;
//定义前后端协议
public class Result {
private Object data;
public Integer code;
private String msg;
public Result() {
}
public Result(Object data, Integer code) {
this.data = data;
this.code = code;
}
public Result(Object data, Integer code, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
然后在controller里新建一个code,java
来定义code码
package cn.calendo.controller;
public class Code {
public static final Integer SAVE_OK = 20011;
public static final Integer UPDATE_OK = 20021;
public static final Integer DELETE_OK = 20031;
public static final Integer SELECT_OK = 20041;
public static final Integer SAVE_ERR = 20010;
public static final Integer UPDATE_ERR = 20020;
public static final Integer DELETE_ERR = 20030;
public static final Integer SELECT_ERR = 20040;
}
这时我们在UserController
里面所返回的值就需要改动了
package cn.calendo.controller;
import cn.calendo.pojo.User;
import cn.calendo.service.UserService;
import com.alibaba.druid.support.json.JSONUtils;
import com.sun.org.apache.xml.internal.serializer.Serializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.filter.CharacterEncodingFilter;
import java.io.Serializable;
import java.util.List;
//设置组件名,给springmvc加载,以及虚拟路径
@RestController
@RequestMapping("/users")
public class UserController {
//也是自动装配,调用service层
@Autowired
private UserService userService;
//post请求,参数实体类,用json传数据
@PostMapping
public Result addUser(@RequestBody User user) {
boolean flag = userService.addUser(user);
return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR, flag);
}
//put请求,参数实体类,用json传数据
@PutMapping
public Result updateUser(@RequestBody User user) {
boolean flag = userService.updateUser(user);
return new Result(flag ? Code.UPDATE_OK : Code.UPDATE_ERR, flag);
}
//delete请求,参数id,用路径传递
@DeleteMapping("/{id}")
public Result deleteUser(@PathVariable Integer id) {
boolean flag = userService.deleteUser(id);
return new Result(flag ? Code.DELETE_OK : Code.DELETE_ERR, flag);
}
//get请求,参数id,用路径传递
@GetMapping("/{id}")
public Result selectUserById(@PathVariable Integer id) {
User user = userService.selectUserById(id);
Integer code = (user != null ? Code.SELECT_OK : Code.SELECT_ERR);
String msg = (user != null ? "" : "数据查询失败!");
return new Result(code, user, msg);
}
//get请求,无参数
@GetMapping
public Result selectAllUser() {
List<User> ListUser = userService.selectAllUser();
Integer code = (ListUser != null ? Code.SELECT_OK : Code.SELECT_ERR);
String msg = (ListUser != null ? "" : "数据查询失败!");
return new Result(code, ListUser, msg);
}
}
测试之后,成功
新建一个拦截异常类在controller层
//使用这个写好的aop
@RestControllerAdvice
public class ProjectExceptionAdvice {
//此注解可以拦截指定异常
@ExceptionHandler(Exception.class)
public Result doException(Exception e) {
System.out.println("拦截到异常");
return new Result(404, null,"拦截到异常");
}
}
新建异常包处理各种异常
package cn.calendo.exception;
public class SystemException extends RuntimeException {
private Integer code;
public Integer getCode() {
return code;
}
public SystemException(Integer code) {
this.code = code;
}
public SystemException(Integer code, String message) {
super(message);
this.code = code;
}
public SystemException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
public SystemException(Integer code, Throwable cause) {
super(cause);
this.code = code;
}
public SystemException(Integer code, String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
this.code = code;
}
}
由于springmvc会把webapp里的东西全部拦截,所以我们需要放行
新建一个叫SpringMVCSupport
的访问放行配置
@Configuration
public class SpringMVCSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
然后让SpringMVCConfig
去扫描
@ComponentScan({"cn.calendo.controller", "cn.calendo.config"})
我们写一下getAll即可获取到全部数据
然后把新增业务做出来
修改功能:
vue methods:
methods: {
//列表
getAll() {
axios.get("/users").then((res) => {
this.dataList = res.data.data;
})
},
//弹出添加窗口
handleCreate() {
this.resetForm();
this.dialogFormVisible = true;
},
//重置表单
resetForm() {
this.formData = {};
},
//添加
handleAdd() {
axios.post("/users", this.formData).then((res) => {
if (res.data.code === 20011) {
this.dialogFormVisible = false;
this.$message.success("添加成功" + " " + "status: " + res.data.code);
} else if (res.data.code === 20010) {
this.$message.error("添加失败" + " " + "status: " + res.data.code);
} else {
this.$message.error(res.data.msg)
}
this.dialogFormVisible = false;
this.getAll();
}).finally(() => {
this.getAll();
});
},
//弹出编辑窗口
handleUpdate(row) {
axios.get("/users/" + row.id).then((res) => {
if (res.data.code === 20041) {
this.formData = res.data.data;
this.dialogFormVisible4Edit = true;
} else {
this.$message.error(res.data.msg);
}
})
},
//编辑
handleEdit() {
axios.put("/users", this.formData).then((res) => {
if (res.data.code === 20021) {
this.dialogFormVisible4Edit = false;
this.$message.success("修改成功" + " " + "status: " + res.data.code);
} else if (res.data.code === 20020) {
this.$message.error("修改失败" + " " + "status: " + res.data.code);
} else {
this.$message.error(res.data.msg)
}
this.dialogFormVisible4Edit = false;
this.getAll();
}).finally(() => {
this.getAll();
});
},
// 删除
handleDelete(row) {
this.$confirm("此操作永久删除当前数据,是否继续?", "警告", {type: 'info'}).then(() => {
axios.delete("/users/" + row.id).then((res) => {
if (res.data.code === 20031) {
this.$message.success("删除成功" + " " + "status: " + res.data.code);
} else if (res.data.code === 20030) {
this.$message.error("删除失败" + " " + "status: " + res.data.code);
} else {
this.$message.error(res.data.msg);
}
}).finally(() => {
this.getAll();
});
}).catch(() => {
this.$message.info("取消删除");
})
}
}
springmvc独有的拦截器
和之前的转发一样的写法
先在springmvcConfig
里面写好能扫描到拦截器的路径
这是SpringMvcSupportConfig
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
}
}
然后开始新建拦截器
拦截器
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
@Override
//原始方法调用前执行的内容
//返回值类型可以拦截控制的执行,true放行,false终止
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String contentType = request.getHeader("Content-Type");
HandlerMethod hm = (HandlerMethod)handler;
System.out.println("preHandle..."+contentType);
return true;
}
@Override
//原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
其实在springmvcconfig
里面也可以直接继承WebMvcConfigurer
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
@Autowired
private ProjectInterceptor projectInterceptor;
@Autowired
private ProjectInterceptor2 projectInterceptor2;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//配置多拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");
}
}