✨✨个人主页:沫洺的主页
📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏
📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏
📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏
💖💖如果文章对你有所帮助请留下三连✨✨
🎨前言
在上一章中提到通过登录页与后端接口进行整合,通过对响应体进行封装,在响应拦截器中获取
💦搭建后端接口
💨💨创建maven Web项目,基于SpringMVC,Druid(德鲁伊数据库连接池)
🎊项目目录结构
📌pom.xml导入坐标依赖,配置tomcat
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.moming</groupId> <artifactId>vue3-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <!--servlet运行环境--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--JavaBean--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> <scope>compile</scope> </dependency> <!--引入webmvc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.2</version> </dependency> <!--标准库--> <dependency> <groupId>org.apache.taglibs</groupId> <artifactId>taglibs-standard-impl</artifactId> <version>1.2.5</version> </dependency> <!--引入jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.0</version> </dependency> <!--Freemarker--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.3.2</version> </dependency> <!--德鲁伊数据库连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!--e-mile--> <dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <!--端口号--> <port>8080</port> <!--虚拟目录--> <path>/moming</path> <!--解决tomcat7及以前get乱码--> <uriEncoding>utf-8</uriEncoding> </configuration> </plugin> </plugins> </build> </project>
📌web.xml配置前端控制器DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--②配置前端控制器DispatcherServlet--> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <url-pattern>/</url-pattern> <!-- / 代表: 所有请求都交给springDispatcherServlet处理--> </servlet-mapping> </web-app>
📌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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--spring就会去自动扫描base-package对应的路径或者该路径的子包下面的java文件, 如果扫描到文件中带有@Service,@Component,@Repository,@Controller等这些注解的类,则把这些类注册为bean--> <!--③扫描子包下的Java文件,根据注解注册bean--> <context:component-scan base-package="com.moming"/> </beans>
📌config/WebConfig编写配置信息
package com.moming.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; import java.nio.charset.StandardCharsets; import java.util.List; //④创建包,创建Config配置类,实现WebMvcConfigurer接口 @Configuration//声明当前类是一个配置类,相当于 Spring 中的一个 XML 文件 @EnableWebMvc//启用spring mvc,支持自定义spring mvc配置的能力 public class WebConfig implements WebMvcConfigurer { //视图配置 @Override public void configureViewResolvers(ViewResolverRegistry registry) { WebMvcConfigurer.super.configureViewResolvers(registry); registry.viewResolver(freeMarkViewResolver()); } //配置视图解析器使用FreeMark模板引擎 private ViewResolver freeMarkViewResolver(){ FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver(); //请求视图的文件后缀 viewResolver.setSuffix(".html"); viewResolver.setContentType("text/html;charset=UTF-8"); viewResolver.setRequestContextAttribute("rca"); return viewResolver; } @Bean public FreeMarkerConfigurer freeMarkerConfigurer(){ FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer(); freeMarkerConfigurer.setTemplateLoaderPath("WEB-INF/html/"); freeMarkerConfigurer.setDefaultEncoding("UTF-8"); return freeMarkerConfigurer; } //解决返回值中文乱码 @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { for (HttpMessageConverter<?> converter:converters){ if(converter instanceof StringHttpMessageConverter){ ((StringHttpMessageConverter)converter).setDefaultCharset(StandardCharsets.UTF_8); } if(converter instanceof MappingJackson2HttpMessageConverter){ ((MappingJackson2HttpMessageConverter)converter).setDefaultCharset(StandardCharsets.UTF_8); } } } }
📌druid.properties 配置德鲁伊数据库连接池
注意这里的信息需要是自己的库,账号,密码
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql:///db5?useSSL=false&useServerPrepStmts=true username=root password=123456 # ??????? initialSize=5 # ????? maxActive=10 # ?????? maxWait=3000
📌config/DbConfig编写连接池配置信息
package com.moming.config; import com.alibaba.druid.pool.DruidDataSourceFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.support.TransactionTemplate; import javax.sql.DataSource; import java.io.InputStream; import java.util.Properties; @Configuration public class DbConfig { /** * 手动注册 Druid dataSource 数据源 * @return DataSource */ @Bean public DataSource dataSource() throws Exception { InputStream resourceAsStream = DbConfig.class.getClassLoader().getResourceAsStream("druid.properties"); Properties prop = new Properties(); prop.load(resourceAsStream); DataSource dataSource = DruidDataSourceFactory.createDataSource(prop); return dataSource; } /** * 手动注册 JdbcTemplate * @return JdbcTemplate */ @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource){ JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } /** * 事务管理器 * @param dataSource * @return */ @Bean public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource){ DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } /** * 事务模板 * @param dataSourceTransactionManager * @return */ @Bean public TransactionTemplate transactionTemplate(DataSourceTransactionManager dataSourceTransactionManager){ TransactionTemplate transactionTemplate = new TransactionTemplate(dataSourceTransactionManager); //transactionTemplate.setTransactionManager(dataSourceTransactionManager); return transactionTemplate; } }
📌model/User实体类
package com.moming.model; import lombok.Data; @Data public class User { private Integer id; private String email; private String password; private String vcode; }
📌dto/UserDto数据传输对象类
package com.moming.dto; import lombok.Data; @Data public class UserDto { private Integer id; private String email; }
📌dto/UserLoginDto数据传输对象类
package com.moming.dto; import lombok.Data; @Data public class UserLoginDto { private String email; private String password; }
📌controller/UserController接口层
package com.moming.controller; import com.moming.dto.UserDto; import com.moming.dto.UserLoginDto; import com.moming.service.UserService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; @Controller @RequestMapping("/api/user") public class UserController { @Resource private UserService userService; @PostMapping("/login") @ResponseBody public UserDto login(@RequestBody UserLoginDto userLoginDto ) throws Exception { UserDto userDto = userService.login(userLoginDto); return userDto; } }
📌service/UserService业务层
package com.moming.service; import com.moming.dao.UserDao; import com.moming.dto.UserDto; import com.moming.dto.UserLoginDto; import com.moming.model.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired private UserDao userDao; public UserDto login(UserLoginDto userLoginDto) throws Exception { //省略验证 User user = userDao.login(userLoginDto.getEmail(), userLoginDto.getPassword()); if(user == null){ throw new Exception("账户或密码不正确"); } UserDto userDto = new UserDto(); userDto.setEmail(user.getEmail()); userDto.setId(user.getId()); return userDto; } }
📌model/UserRowMapper映射文件
package com.moming.model; import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; import java.sql.SQLException; public class UserRowMapper implements RowMapper<User> { @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { // 对数据的返回处理 User order = new User(); order.setId(rs.getInt("id")); order.setEmail(rs.getString("email")); order.setPassword(rs.getString("password")); return order; } }
📌dao/UserDao数据访问层
注意这里查询的表名为user_email表
package com.moming.dao; import com.moming.model.User; import com.moming.model.UserRowMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.util.List; @Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public User login(String email, String password){ String sql = "select id,email,password from user_email where email = ? and password =? limit 1 "; List<User> userList = jdbcTemplate.query(sql, new UserRowMapper(),email,password); if(userList.size() > 0){ return userList.get(0); } return null; } }
💦数据库表结构
💦安装RestfulTool插件
📌使用RestfulTool
📌发送json数据验证是否请求成功(注意是运行状态下发送请求)
📌
🍂前端代理接口
📌修改代理接口路径
📌创建api/userApi.ts,并通过api/index.ts去导入
📌 api/userApi.ts
import http from "@/http/index" const userApi = { login:{ name:"用户登录", url:"/api/user/login", call: async function (params:any) { return await http.post(this.url,params); } }, } export default userApi;
📌api/index.ts
import productApi from "./ProductApi"; import orderApi from "./orderApi"; import userApi from "./userApi"; export {productApi,orderApi,userApi}
📌UserLogin.vue导入userApi
📌使用userApi
📌看效果,填写的是数据库中的邮箱和密码
📌填写数据库中不存在的邮箱和密码
📌接下来要实现的就是将用户信息通过pinia本地存储,在登录成功后显示用户账号
📌在store/appStore.ts中定义用户id和账号email
📌 在UserLogin.vue中导入,并在校验成功后将用户登录的信息进行赋值
📌查看本地存储
📌 实现登陆后显示用户名
📌 只需要导入即可
📌退出登录后就应该销毁本地存储
🍂遵循协议约定统一返回json格式,统一异常处理
📌统一返回json格式
📌新建dto/ResponseDto
package com.moming.dto; import lombok.Data; @Data public class ResponseDto { private int code; private String message; private Object data; }
📌统一异常处理
📌新建advice/MyResponseAdvice
package com.moming.advice; import com.moming.dto.ResponseDto; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; /** * 拦截器 */ @ControllerAdvice//是一个增强的Controller @ResponseBody//返回json格式数据 public class MyResponseAdvice implements ResponseBodyAdvice<Object> { //统一异常处理 @ExceptionHandler(Exception.class)//可以拦截特点的异常,因此可以更精确的配置异常处理逻辑 public Object processException(Exception ex){ ResponseDto responseDto = new ResponseDto(); //走到这里一定是有异常,code=0正常,code=1异常 responseDto.setCode(1); responseDto.setMessage(ex.getMessage()); //data为空 return responseDto; } @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { //如果已经报错(使用ResponseBody包装过)了就直接返回,通过类型进行判断 if(body instanceof ResponseDto){ return body; } ResponseDto responseDto = new ResponseDto(); responseDto.setCode(0); responseDto.setMessage(""); responseDto.setData(body); return responseDto; } }
📌 同样的对于正确的信息也要使用这种返回体格式进行包装
📌注意有个细节点,当出现异常后,body就会走统一异常处理包成那种code message data的协议格式,也就是类型变为ResponseDto这种类型,但是图中提到,所有的接口都走下边的beforeBodyWrite方法,如果对异常协议格式再次进行包装就会又变成正确的code=0
📌效果图
🎨总结说明
💖💖code message data的这种协议格式是在实际开发过程中,我们经常要返回数据给前台,这时候就需要定义返回的code message和data