前后端分离的web项目-后端-springboot框架
创建项目时的选项
结构目录
- src/main/java
- main
- 前缀.aop
- 前缀.controller
- 前缀.entity
- 前缀.ex
- 前缀.interceptor
- 前缀.mapper
- 前缀.service
- 前缀.service.impl
- 前缀.thread
- 前缀.webSocket
- src/main/resources
- mappers
- application.properties
#数据库路径 spring.datasource.url = jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterCoding=utf-8&&serverTimezone=Asia/Shanghai #数据库用户名 spring.datasource.username = root #数据库密码 spring.datasource.password = root #上传文件最大限制 spring.servlet.multipart.max-file-size = 100MB #mapper映射路径 mybatis.mapper-locations = classpath:mappers/*.xml
步骤
-
创建所有目录结构、配置application.properties文件
-
启动类配置扫描注解
#启动注解 @SpringBootApplication #扫描mapper包 @MapperScan("前缀.mapper") #扫描所有包 @ComponentScan(basePackages = "前缀")
-
设计数据库、创建对应的实体类
在‘前缀.entity’包下
实体类需要实现Serializable接口implements Serializable{ /** * */ private static final long serialVersionUID = 1L;
-
在‘前缀.mapper’包下创建对应数据库增删改查等功能的接口
-
创建对应mapper接口的实现功能的SQL语句的xml
在‘mappers’目录下
xml文件中添加约束<!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
-
设计service异常类及其派生出的异常类
在‘前缀.ex’包
public class ServiceException extends RuntimeException{ /** * */ private static final long serialVersionUID = 1L; public ServiceException() { super(); } public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } public ServiceException(String message, Throwable cause) { super(message, cause); } public ServiceException(String message) { super(message); } public ServiceException(Throwable cause) { super(cause); } }
-
设计返回结果类型
public class Result<T> implements Serializable { /** * */ private static final long serialVersionUID = 1L; private Integer state; private String message; private T data; public Result(Integer state, Exception e) { super(); this.state = state; this.message = e.getMessage(); } //以及get、set和根据属性的构造方法 }
-
设计controller的基类(处理异常类)
在‘前缀.controller’包
/** * 控制器类的基类 * @author Thomas Adam * */ public class BaseController { /** * 处理请求时,用于表示操作正确的代码 */ public static final int SUCCESS=200; /** * 处理用户数据请求时发生的异常 * @param e 异常 * @return 异常数据,处理结果 */ @ExceptionHandler(ServiceException.class) public Result<Void> handleException(Exception e){ //声明返回对象 Result<Void> rr=new Result<Void>(); //在返回对象中封装错误提示的文字 rr.setMessage(e.getMessage()); //根据异常的不同,返回的错误代码也不同 if(e instanceof UserConflictException) { //用户名冲突 rr.setState(400); }else if(e instanceof UserNotFoundException) { //用户不存在 rr.setState(401); }else if(e instanceof PasswordNotMatchException) { //密码验证失败 rr.setState(402); }else if(e instanceof TaskNotFoundException){ //用户没有任务信息 rr.setState(403); }else if(e instanceof InsertException) { //插入数据时发生异常 rr.setState(500); }else if(e instanceof UpdateException) { //更新数据时发生异常 rr.setState(501); }else if(e instanceof NotLoginException) { //未登录或登录信息失效 rr.setState(601); } //返回 return rr; } /** * 从session中获取当前登录用户的ID * @param session * @return 当前登录用户的ID */ protected Integer getUidFromSession(HttpSession session) { return Integer.valueOf(session.getAttribute("uid").toString()); } }
-
设计controller类、设计api接口
在‘前缀.controller’包
@RestController @RequestMapping("users") public class UserController extends BaseController
-
根据api接口,设计对应的接口及抽象方法
在‘前缀.service’包
抛出可能存在的异常 -
实现‘前缀.service’中的接口,编写具体步骤
在‘前缀.service.impl’包
实现类上加注解:@Service -
调用service接口、完善controller类
-
设计websocket连接
‘前缀.webSocket’包
- 连接处理类
@ServerEndpoint(value="/webSocket/{uid}",configurator = HttpSessionConfigurator.class) @Component public class MyWebSocket { //在线人数 private static int onlineCount=0; private static Map<Integer, MyWebSocket> socketMap = new ConcurrentHashMap<>(); private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<>(); private Session session; @OnOpen public void onOpen(Session session,@PathParam("uid") String uid) { this.session = session; sendMessage("连接成功!"); System.out.println("有新连接加入!"); Integer id = Integer.valueOf(uid); socketMap.put(id, this); addOnlineCount(); webSocketSet.add(this); System.out.println("当前在线人数为:"+getOnlineCount()); System.out.println("用户ID:"+id); } @OnClose public void onClose() { if(webSocketSet.size()>=1) { webSocketSet.remove(this); for (Integer uid : socketMap.keySet()) { MyWebSocket mws = socketMap.get(uid); if(mws.equals(this)) { socketMap.remove(uid); break; } } } if(getOnlineCount()>=1)subOnlineCount(); System.out.println("有一连接关闭!当前在线人数为:"+getOnlineCount()); } @OnMessage public void onMessage(String message,Session session) { System.out.println("来自客户端--"+session.getId()+"--的消息:"+message); } @OnError public void onError(Session session,Throwable error) { if(error instanceof NotLoginException)return; System.err.println(error.getMessage()); System.out.println(error); } public synchronized void sendMessage(String message) { try { this.session.getBasicRemote().sendText(message); System.out.println("---------向客户端发送信息----------"); System.out.println(message); System.out.println("------------------------"); } catch (IOException e) { e.printStackTrace(); } } public static int getOnlineCount() { return onlineCount; } private static synchronized void addOnlineCount() { MyWebSocket.onlineCount++; } private static synchronized void subOnlineCount() { MyWebSocket.onlineCount--; } public static synchronized CopyOnWriteArraySet<MyWebSocket> getWebSocketSet() { return webSocketSet; } public static Map<Integer, MyWebSocket> getSocketMap() { return socketMap; } public Session getSession() { return session; } }
- 配置类
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
- 连接处理类
-
设计拦截器
前缀.interceptor包
- 未登录处理
@Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object object = request.getSession().getAttribute("username"); if(object==null) { throw new NotLoginException("请登录!"); } return true; } }
- 拦截器
@Configuration public class InterceptorConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { //创建拦截器对象 HandlerInterceptor interceptor=new LoginInterceptor(); //白名单 List<String> list=new ArrayList<>(); list.add("/"); list.add("/users/reg"); list.add("/users/login"); //添加拦截器 registry.addInterceptor(interceptor).addPathPatterns("/**").excludePathPatterns(list); } /** * (jar包)添加动态生成资源的路径 * 请求时转向此路径 */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/excel/**").addResourceLocations("file:"+UploadPathUtils.getExcelPath()); WebMvcConfigurer.super.addResourceHandlers(registry); } }
- 未登录处理
-
多线程(异步线程)
'前缀.thread'包
- 配置类
//配置注解 @Configuration //启动异步注解 @EnableAsync public class ThreadConfig { @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //核心线程数量 executor.setCorePoolSize(1); //最大线程数量 executor.setMaxPoolSize(1); //任务队列 executor.setQueueCapacity(20); return executor; } }
- 实现类
@Component public class Hello { @Async public void sayHello(String name) { System.err.println(System.currentTimeMillis()); System.err.println("处理任务中........"); try { Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } System.err.println(name+":Hello World!"); } }
- 配置类
-
切面编程
'前缀.aop'包
调用异步线程//切面注解 @Aspect @Component public class AopTaskController { @Autowired //自动装配异步线程类 //切入点 @Pointcut(value = "execution(public * taobao.controller.TaskController.addNewTask(..))") public void handleTask() {}; @Pointcut(value = "execution(public * taobao.controller.TaskController.addGoodsTask(..))") public void goodsTasks() {} //切入点方法执行前执行 @Before("handleTask()") public void berforeHandle() { } //切入点方法完成后执行 @AfterReturning(returning = "obj", pointcut = "handleTask()") public void afterReturning(Object obj) { handleDo(obj); } @AfterReturning(returning = "obj", pointcut = "goodsTasks()") public void afterGoodsTask(Object obj) { handleDo(obj); } private void handleDo(Object obj) { //逻辑功能 //调用异步线程 } }