基于RESRful页面数据交互
1.制作SpringMVC控制器,并通过PostMan测试接口功能
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public String save(@RequestBody Book book){
System.out.prinln("book save ==>" + book);
return "{'module':'book save success'}";
}
@GetMapping
public List<Book> getAll(){
System.out.println("book getAll is runing ...");
List<Book> bookList = new ArrayList<Book>();
Book book1 = new Book();
book1.setType("计算机");
book1.setName("SpringMVC入门教程")
book1.setDescription("小试牛刀")
bookList.add(book1);
//模拟数据...
return bookList;
}
}
2.设置对静态资源的访问放行
//放行非springmvc的请求
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
// 当访问/pages/???时,走/pages目录下的内容
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
}
3.前端页面通过异步提交访问后台控制器
//添加
saveBook(){
axios.post("/books",this.formData).then((res)=>{
});
},
//主页列表查询
getAll(){
axios.get("/books").then((res)=>{
this.dataList = res.data;
});
};
5.SSM整合
1.整合配置
JdbcConfig
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
MybatisConfig
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setTypeAliasesPackage("com.zkw.domain");
return factoryBean;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.zkw.dao");
return msc;
}
}
ServletConfig
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
SpringConfig
@Configuration
@ComponentScan({"com.zkw.service"})
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class, MybatisConfig.class})
public class SpringConfig {
}
SpringMvcConfig
@Configuration
@ComponentScan("com.zkw.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
2.功能模块开发
BookController
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public boolean save(@RequestBody Book book) {
return bookService.save(book);
}
@DeleteMapping("/{id}")
public boolean delete(@PathVariable Integer id) {
return bookService.delete(id);
}
@PutMapping
public boolean update(@RequestBody Book book) {
return bookService.update(book);
}
@GetMapping("/{id}")
public Book getById(@PathVariable Integer id) {
return bookService.getById(id);
}
@GetMapping
public List<Book> getAll() {
return bookService.getAll();
}
}
BookService
public interface BookService {
public boolean save(Book book);
public boolean delete(Integer id);
public boolean update(Book book);
public Book getById(Integer id);
public List<Book> getAll();
}
BookServiceImpl
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Override
public boolean save(Book book) {
bookDao.save(book);
return true;
}
@Override
public boolean delete(Integer id) {
bookDao.delete(id);
return true;
}
@Override
public boolean update(Book book) {
bookDao.update(book);
return true;
}
@Override
public Book getById(Integer id) {
return bookDao.getById(id);
}
@Override
public List<Book> getAll() {
return bookDao.getAll();
}
}
BookDao
public interface BookDao {
@Insert("insert into tbl_book values(null,#{type},#{name},#{description})")
public void save(Book book);
@Update("update tbl_book set type=#{type},name=#{name},description=#{description} where id=#{id}")
public void update(Book book);
@Delete("delete from tbl_book where id = #{id}")
public void delete(Integer id);
@Select("select * from tbl_book where id = #{id}")
public Book getById(Integer id);
@Select("select * from tbl_book")
public List<Book> getAll();
}
Book
public class Book {
private Integer id;
private String type;
private String name;
private String description;
@Override
public String toString() {
return "Book{" +
"id=" + id +
", type='" + type + '\'' +
", name='" + name + '\'' +
", description='" + description + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
事务处理
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager ds = new DataSourceTransactionManager();
ds.setDataSource(dataSource);
return ds;
}
3.接口测试
BookServiceTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {
@Autowired
private BookService bookService;
@Test
public void testGetById(){
Book book =bookService.getById(1);
System.out.println(book);
}
@Test
public void testGetAll(){
List<Book> all =bookService.getAll();
System.out.println(all);
}
}
再用PostMan去测试增删改查功能是否成功
6.表现层和前端数据传输协议
设置统一数据返回结果类
public class Result {
private Object data;
private Integer code;
private String msg;
}
通过code可以得知,是增删改查何种操作,最后的数字,1代表成功,0代表失败
-
20031 -> 增删改
-
20041 -> 查询
编写Code
public class Code {
public static final Integer SAVE_OK = 20011;
public static final Integer DELETE_OK = 20021;
public static final Integer UPDATE_OK = 20031;
public static final Integer GET_OK = 20041;
public static final Integer SAVE_ERR = 20010;
public static final Integer DELETE_ERR = 20020;
public static final Integer UPDATE_ERR = 20030;
public static final Integer GET_ERR = 20040;
}
修改BookController
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public Result save(@RequestBody Book book) {
boolean flag = bookService.save(book);
return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag);
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
boolean flag = bookService.delete(id);
return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag);
}
@PutMapping
public Result update(@RequestBody Book book) {
boolean flag = bookService.update(book);
return new Result(flag ? Code.UPDATE_OK:Code.UPDATE_ERR,flag);
}
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
Book book = bookService.getById(id);
Integer code = book != null ? Code.GET_OK:Code.GET_ERR;
String msg = book != null ? "":"数据查询失败 请重试";
return new Result(code,book,msg);
}
@GetMapping
public Result getAll() {
List<Book> bookList = bookService.getAll();
Integer code = bookList != null? Code.GET_OK:Code.GET_ERR;
String msg = bookList !=null ? "":"数据查询失败 请重试";
return new Result(code,bookList,msg);
}
}
7.异常处理器
由于各个层级均会出现异常,所以将所有的异常均抛出到表现层处理
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(Exception.class)
public Result doException(Exception e){
System.out.println("已发现异常");
return new Result(666,null,"已发现异常");
}
}
通过@RestControllerAdvice声明其为一个异常处理器
再通过@ExceptionHandler来定义处理哪一种异常
8.项目异常处理方案
-
业务异常(BusinessException)
- 发送对应消息传递给用户,提醒规范操作
-
系统异常(SystemException)
-
发送固定信息传递给用户,安抚用户
-
发送特定消息给运维人员,提醒维护
-
记录日志
-
-
其他异常(Exception)
-
发送固定消息传递给客户,安抚客户
-
发送特定消息给编程人员,提醒维护(纳入预期范围)
-
记录日志
-
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException e){
//记录日志
//发送消息给运维
//发送邮件给开发人员
return new Result(e.getCode(),null,e.getMessage());
}
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException e){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发给开发人员
return new Result(e.getCode(),null,e.getMessage());
}
@ExceptionHandler(Exception.class)
public Result doException(Exception e){
System.out.println("已发现异常");
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试");
}
}
要根据对应的异常,设定相应的异常编码
自定义项目级系统异常
public class SystemException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(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;
}
}
9.前后台协议联调
method: {
//列表功能
getAll() {
//发送ajax请求
axios.get("/books").then((res)=>{
this.dataList = res.data.data;
});
},
//重置表单
resetForm(){
this.formData = {};
},
//添加
handleAdd(){
//发送ajax请求
axios.post("/books",this.formData).then((res)=>{
//如果操作成功,关闭弹层,显示数据
if(res.data.code == 20011){
this.dialogFormVisible = false;
this.$message.success("添加成功");
}else if(res.data.code == 20010){
this.$message.error("添加失败");
}else{
this.$message.error("res.data.msg");
}
}).finally()=>{
this.getAll();
});
},
//弹出编辑窗口
handleUpdate(row){
//console.log(row); //row.id 查询条件
//查询数据,根据id
if(res.data.code == 20041){
//展示弹层,加载数据
this.formData = res.data.data;
this.diagloFormVisible4Edit = true;
}else{
this.$message.error("res.data.msg");
}
});
},
//编辑
handleEdit(){
//发送ajax请求
axios.pup("/books",this.formData).then((res)=>{
//如果操作成功,关闭弹层,显示数据
if(res.data.code == 20031){
this.dialogFormVisible4Edit = false;
this.$message.success("修改成功");
}else if(res.data.code == 20030){
this.$message.error("修改失败");
}else{
this.$message.error("res.data.msg");
}
}).finally()=>{
this.getAll();
});
},
// 删除
handleDelete(row) {
//1.弹出提示框
this.$confirm("此操作永久删除当前数据,是否继续?","提示",{
type:'info'
}).then((=>{
//2.做删除业务
axios.delete("/books/"+row.id).then((res)=>{
if(res.data.code == 20021){
this.$message.success("删除成功")
}else{
this.$message.error("删除失败");
}
});
}).catch(()=>{
//3.取消删除操作
this.$message.info("取消删除操作");
}).finally(()=>{
this.getAll();
});
}
}
})
10.拦截器
**拦截器概念:**是一种动态拦截方法调用的机制,再SpringMVC中动态拦截控制器方法的执行
**作用:**在指定的方法调用前后执行预先设定的代码;阻止原始方法的执行
拦截器与过滤器区别:
-
归属不同:Filter属于Servlet技术,Interecptor属于SpringMVC技术
-
拦截内容不同:Filter对所有访问进行增强,Interecptor仅针对SpringMVC的访问进行增强
拦截器入门案例:
1.声明拦截器的bean,并实现HandlerInterceptor接口
@Component
public class ProjectInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...");
return true; //false可终止原始操作
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
2.定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
}
拦截器配置
拦截器可以配多个,形成拦截链
-
preHandle:与配置顺序相同,必定运行
-
postHandle:与配置顺序相反,可能不运行
-
afterCompletion:与配置顺序相反,可能不运行