MySql+SpringBoot+Vue 搭建一个完整的前后端分离项目

完整项目搭建流程

虽说 SpringBoot 相较于 SSM 框架,大大减轻了配置的繁琐,但是,要整合 MyBatis ,统一异常处理,Vue等一系列东西,还是要费一番劲的。

这次将创建的整个流程记录下来,方便以后的项目搭建。

要搭建一个完成的前后端分离项目,分为这么几个部分:数据库、后端、前端

如果是为微信小程序搭建一个后端服务,那就只要看到数据库、后端就可以了

数据库

一般在新建项目的时候,我们会选择专门为这个项目新建一个用户,并为这个用户,赋予只属于这一个项目的所有权限

1. 连接 admin

只有 admin 有所有权限

我的数据库 admin 的账户名和密码是:

**账户:**admin

**密码:**123

image-20210411002100312

2. 新建数据库

其字符类型一定要选择utf8mb4,这才是真正的 utf8,支持表情符号

image-20210411002304858

3. 为这个数据库,专门建一个用户

开发环境中,就将密码和用户名设置成一样的,这样不会忘记

host 设置为 localhost

image-20210411002742750

4. 为这个用户,授予对应数据库的全部权限

image-20210411003034426

image-20210411002821790

5. 对当前用户,建立连接

image-20210411002945727

后端

关于 Maven、tomcat 的下载配置,这里就不费笔墨去讲解了。如有需要,可以自行百度查找。

1. 新建 SpringBoot 项目

  • 点击 SpringInitiallizr,新建项目

image-20210414200239335

  • 选择默认依赖的包

image-20210414200420395

image-20210414200533694

image-20210414200611051

  • 选择存放路径

image-20210414200656633

  • 新建完成后,项目目录如下

image-20210414200752152

2. 更改启动类位置

  • 新建 config 包,将启动类放进去

image-20210414201018806

  • 为启动类添加注解

注解内的信息,是项目名称

@ComponentScan("weixindemo")

image-20210414201210978

3. IDEA 数据库配置

  • IDEA 连接数据库

image-20210414220153821

image-20210414221502868

  • 添加 sql 脚本

新建 sql 文件夹,建立all.sql文件

image-20210414221647283

我们在 sql 脚本中添加测试用数据,并执行

# 测试表
drop table if exists `test`;
create table `test` (
  `id` bigint not null comment 'id',
  `name` varchar(50) comment '名称',
  `password` varchar(50) comment '密码',
  primary key (`id`)
) engine=innodb default charset=utf8mb4 comment='测试';

insert into `test` (id, name, password) values (1, '测试', 'password');       

可以看到,数据库已建立

image-20210415000115932

4. 配置 MyBatis

  • resource文件夹下,新建 mapper文件夹

这是用来存放 MyBatis 的实现的

image-20210414201459632

  • 新建 pojo 包

pojo 包用来存放实体类

image-20210415000316772

  • 在项目下,新建 mapper 包,用来存放接口

image-20210415000711989

  • 将配置文件后缀改为.yml

我个人习惯使用.yml进行位置

image-20210414201610045

  • 添加 Mybatis配置

这里,要添加数据源,和 MyBatis 的配置,部分地方,要根据实际项目,进行修改

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/weixindemo?useUnicode=true&characterEncoding=utf-8
    username: weixindemo
    password: weixindemo
    driver-class-name: com.mysql.cj.jdbc.Driver
    
    
# 整合Mybatis
mybatis:
  # ** 表示在mapper下不管有多少文件夹,都可以全部识别
  mapper-locations: classpath:/mapper/**/*.xml
  type-aliases-package: weixindemo.pojo
  #  打印sql相关的日志信息
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

image-20210415000535841

  • 添加端口配置

因为 vue 也是用的8080端口,我们不能和它重了

server:
  port: 8880
  • 启动类添加mapper接口扫描路径
@MapperScan("weixindemo.mapper") //mybatis mapper接口扫描

image-20210415000824262

5. MVC 包建立

我们还要建立 serviceutilcontroller

image-20210415001226689

image-20210415001237989

5. 测试 Mybatis 配置

配置到这一步,要对之前的配置,进行一个测试

  • pojo 中,新建 Test 实体类

image-20210415001028711

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Test {
   
    private Integer id;
    private String name;
}
  • mapper 包中,新建 TestMapper 接口

image-20210415001403532

@Repository
@Mapper
public interface TestMapper {
   
    List<Test> getList();
}
  • resources 下的 mapper 文件夹中,增加 TestMapper.xml 实现

    image-20210415002153386

具体内容,要根据实际项目修改

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace要和接口的位置和名字对应-->
<mapper namespace="weixindemo.mapper.TestMapper">

    <select id="getList" resultType="weixindemo.pojo.Test">
        select * from test
    </select>

</mapper>

image-20210415002240288

  • 在 service 包下,新建 TestService

别忘了加上 @Service 注解

@Service
public class TestService {
   

    @Autowired
    private TestMapper mapper;

    public List<Test> getList() {
   
        return mapper.getList();
    }
}
  • 在 controller包下,新建 TestController

image-20210415002611361

@RestController
public class TestController {
   

    @Autowired
    private TestService testService;
    

    @RequestMapping("/test/list")
    public List<Test> list() {
   
        return testService.getList();
    }

}
  • 重启项目

  • 新建 http 文件,编写 http 测试脚本,执行

image-20210415002803589

GET http://localhost:8880/test/list
Accept: application/json

###

最后成功从接口中获取数据库中的数据,说明我们之前配置的都没有错误,可以进行下面的操作

image-20210415003021769

6. MyBatis 代码生成器

我们不可能去写所有持久层的实现,业务中,这部分都是自动生成的

  • 导入 Maven 依赖

注意,是放在plugiuns下面的

<!-- mybatis generator 自动生成代码插件 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.4.0</version>
                <configuration>
                    <configurationFile>src/main/resources/generator/generator-config.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.22</version>
                    </dependency>
                </dependencies>
            </plugin>
  • 建立代生成器位置

pom文件中,显示了要创建的代码生成器的位置src/main/resources/generator/generator-config.xml

<configurationFile>
  src/main/resources/generator/generator-config.xml
</configurationFile>

image-20210323131202189

  • 代码生成器代码

jdbcConnection开始,别忘了根据项目进行修改

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="Mysql" targetRuntime="MyBatis3" defaultModelType="flat">

        <!-- 自动检查关键字,为关键字增加反引号 -->
        <property name="autoDelimitKeywords" value="true"/>
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        <!--覆盖生成XML文件-->
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
        <!-- 生成的实体类添加toString()方法 -->
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>

        <!-- 不生成注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/wiki?useUnicode=true&amp;characterEncoding=utf-8"
                        userId="wiki"
                        password="123456">
        </jdbcConnection>

        <!-- domain类的位置 -->
        
  • 7
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
好的,下面是一个简单的示例: 1. 后端使用Spring Boot搭建,创建一个名为"login"的Spring Boot项目。 2. 在项目中添加依赖: ```xml <dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Boot Data JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- MySQL Driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- Spring Security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- JSON Web Token --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> </dependencies> ``` 3. 创建一个名为"User"的实体类,用于表示用户信息。 ```java @Entity @Table(name = "users") public class User implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String username; @Column(nullable = false) private String password; @Column(nullable = false) private String role; // getters and setters @Override public Collection<? extends GrantedAuthority> getAuthorities() { return Arrays.asList(new SimpleGrantedAuthority(role)); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } } ``` 4. 创建一个名为"UserRepository"的接口,用于操作用户数据。 ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); } ``` 5. 创建一个名为"JwtUtils"的工具类,用于生成和验证JSON Web Token。 ```java public class JwtUtils { private static final String SECRET_KEY = "secret"; public static String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); claims.put("username", userDetails.getUsername()); claims.put("role", userDetails.getAuthorities().stream().findFirst().get().getAuthority()); return Jwts.builder() .setClaims(claims) .setSubject(userDetails.getUsername()) .setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 1000)) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public static boolean validateToken(String token, UserDetails userDetails) { String username = getUsernameFromToken(token); return username.equals(userDetails.getUsername()) && !isTokenExpired(token); } public static String getUsernameFromToken(String token) { return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject(); } public static boolean isTokenExpired(String token) { return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration().before(new Date()); } } ``` 6. 创建一个名为"JwtAuthenticationFilter"的过滤器,用于处理登录请求并生成JSON Web Token。 ```java public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter { private final AuthenticationManager authenticationManager; public JwtAuthenticationFilter(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; setFilterProcessesUrl("/api/login"); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { User user = new ObjectMapper().readValue(request.getInputStream(), User.class); return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), Collections.emptyList())); } catch (IOException e) { throw new RuntimeException(e); } } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { String token = JwtUtils.generateToken((UserDetails) authResult.getPrincipal()); response.setContentType("application/json"); response.getWriter().write("{\"token\": \"" + token + "\"}"); } } ``` 7. 创建一个名为"SecurityConfig"的配置类,用于配置Spring Security。 ```java @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserRepository userRepository; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(username -> userRepository.findByUsername(username)).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/login").permitAll() .anyRequest().authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .addFilter(new JwtAuthorizationFilter(authenticationManager())) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } } ``` 8. 创建一个名为"JwtAuthorizationFilter"的过滤器,用于验证请求中的JSON Web Token。 ```java public class JwtAuthorizationFilter extends BasicAuthenticationFilter { private static final String HEADER_STRING = "Authorization"; private static final String TOKEN_PREFIX = "Bearer "; public JwtAuthorizationFilter(AuthenticationManager authenticationManager) { super(authenticationManager); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String header = request.getHeader(HEADER_STRING); if (header != null && header.startsWith(TOKEN_PREFIX)) { String token = header.substring(TOKEN_PREFIX.length()); try { String username = JwtUtils.getUsernameFromToken(token); UserDetails userDetails = userDetailsService().loadUserByUsername(username); if (JwtUtils.validateToken(token, userDetails)) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (JwtException e) { SecurityContextHolder.clearContext(); } } chain.doFilter(request, response); } } ``` 9. 前端使用Vue.js搭建,创建一个名为"login"的Vue.js项目。 10. 在项目中安装axios和vue-router: ``` npm install --save axios vue-router ``` 11. 创建一个名为"Login"的组件,用于渲染登录表单。 ```vue <template> <div> <h1>Login</h1> <form @submit.prevent="login"> <div> <label for="username">Username:</label> <input type="text" id="username" v-model="username"> </div> <div> <label for="password">Password:</label> <input type="password" id="password" v-model="password"> </div> <div> <button type="submit">Login</button> </div> </form> </div> </template> <script> import axios from 'axios' export default { data () { return { username: '', password: '' } }, methods: { login () { axios.post('/api/login', { username: this.username, password: this.password }) .then(response => { localStorage.setItem('token', response.data.token) this.$router.push('/') }) .catch(error => { console.error(error) }) } } } </script> ``` 12. 创建一个名为"App"的组件,用于渲染主页面。 ```vue <template> <div> <h1>Home</h1> <div v-if="authenticated"> <p>Welcome, {{ username }}!</p> <button @click="logout">Logout</button> </div> <div v-else> <router-link to="/login">Login</router-link> </div> </div> </template> <script> import axios from 'axios' export default { data () { return { authenticated: false, username: '' } }, created () { axios.get('/api/user') .then(response => { this.authenticated = true this.username = response.data.username }) .catch(error => { console.error(error) }) }, methods: { logout () { localStorage.removeItem('token') this.$router.push('/') location.reload() } } } </script> ``` 13. 创建一个名为"router"的路由配置文件,用于配置Vue.js路由。 ```js import Vue from 'vue' import VueRouter from 'vue-router' import Login from './components/Login.vue' import App from './components/App.vue' Vue.use(VueRouter) const router = new VueRouter({ mode: 'history', routes: [ { path: '/', component: App }, { path: '/login', component: Login } ] }) router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.path !== '/login' && !token) { next('/login') } else { next() } }) export default router ``` 14. 在"index.html"中添加Vue.js和axios的CDN链接: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Login</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> </head> <body> <div id="app"></div> <script src="dist/build.js"></script> </body> </html> ``` 15. 在"main.js"中创建Vue.js实例并挂载到DOM上: ```js import Vue from 'vue' import App from './components/App.vue' import router from './router' new Vue({ el: '#app', router, render: h => h(App) }) ``` 16. 运行项目: ``` mvn spring-boot:run ``` ``` npm run dev ``` 现在你可以在浏览器中访问"http://localhost:8080"来测试登录功能了。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FARO_Z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值