客服热线:139 1319 1678

科研管理系统

科研管理系统在线试用
科研管理系统
在线试用
科研管理系统解决方案
科研管理系统
解决方案下载
科研管理系统源码
科研管理系统
源码授权
科研管理系统报价
科研管理系统
产品报价

26-2-21 03:49

张伟(以下简称张):李娜,最近我们在学校的一个科研项目中要搭建一个科研管理系统,你对后端开发这块有经验,能给我讲讲怎么开始吗?

李娜(以下简称李):当然可以。首先,我们需要明确这个科研系统的功能需求。比如,用户管理、课题申报、成果录入、数据统计等模块。

张:明白了。那你觉得用什么技术栈比较合适呢?我们学校的技术团队主要是用Java的,所以可能优先考虑Java相关的框架。

李:没错,Java生态非常成熟,适合企业级应用开发。推荐使用Spring Boot框架,它简化了配置,提高了开发效率,而且和数据库、安全控制等集成起来也比较方便。

张:听起来不错。那我们可以先搭建一个基本的后端结构。你有没有具体的代码示例可以参考?

李:当然有。我可以给你写一个简单的Spring Boot项目结构,包括依赖、启动类和一个基本的REST接口。

张:太好了,我来记一下。

李:好的,下面是一个Spring Boot项目的pom.xml文件内容,包含必要的依赖:

<?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.example</groupId>
    <artifactId>research-system</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ResearchSystem</name>
    <description>科研系统后端服务</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
    

科研系统

张:这个pom文件看起来很标准。接下来是不是需要创建一个启动类?

李:是的,Spring Boot项目通常有一个主类,用来启动应用。下面是示例代码:

package com.example.researchsystem;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ResearchSystemApplication {
    public static void main(String[] args) {
        SpringApplication.run(ResearchSystemApplication.class, args);
    }
}
    

张:明白了。那如何创建一个简单的REST API呢?比如获取用户信息?

李:我们可以创建一个Controller类。例如,一个UserController,提供一个GET接口来获取用户信息。

张:好的,那具体代码是怎样的?

李:以下是UserController的示例代码:

package com.example.researchsystem.controller;

import com.example.researchsystem.model.User;
import com.example.researchsystem.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public List getAllUsers() {
        return userService.getAllUsers();
    }

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user);
    }

    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
}
    

张:这看起来很完整。那UserService和User实体类又是怎么写的?

李:我们先来看User实体类,它通常对应数据库表结构。以下是示例代码:

package com.example.researchsystem.model;

import jakarta.persistence.*;
import lombok.Data;

@Entity
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
    private String role;
}
    

张:用了Lombok,确实方便。那UserService是怎么实现的?

李:UserService是一个Service层,负责业务逻辑。这里我们使用Spring Data JPA来操作数据库。以下是示例代码:

package com.example.researchsystem.service;

import com.example.researchsystem.model.User;
import com.example.researchsystem.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List getAllUsers() {
        return userRepository.findAll();
    }

    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    public User createUser(User user) {
        return userRepository.save(user);
    }

    public User updateUser(Long id, User user) {
        if (userRepository.existsById(id)) {
            user.setId(id);
            return userRepository.save(user);
        }
        return null;
    }

    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}
    

张:明白了。那UserRepository又是什么?

李:UserRepository是一个接口,继承自JpaRepository,用于定义数据库操作方法。以下是代码示例:

package com.example.researchsystem.repository;

import com.example.researchsystem.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository {
}
    

张:这样整个后端结构就初步完成了。那接下来要考虑的是安全性问题,比如登录认证。

李:是的,安全是科研系统中非常重要的一环。我们可以使用Spring Security来实现基于JWT的认证机制。

张:那能不能也给个代码示例?

李:当然可以。下面是一个简单的JWT认证流程的代码片段,包括生成Token、验证Token以及拦截器的配置。

张:好的,我先看看这部分代码。

李:首先是生成JWT Token的工具类:

package com.example.researchsystem.security;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Component
public class JwtUtil {

    private final String SECRET_KEY = "your-secret-key-here";

    private Key getSignKey() {
        byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
        return Keys.hmacShaKeyFor(keyBytes);
    }

    private String generateToken(Map claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
                .signWith(getSignKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    public String generateToken(String username) {
        return generateToken(new HashMap<>(), username);
    }

    public Boolean isTokenExpired(String token) {
        return extractClaim(token, Claims::getExpiration).before(new Date());
    }

    public  T extractClaim(String token, Function resolver) {
        final Claims claims = extractAllClaims(token);
        return resolver.apply(claims);
    }

    private Claims extractAllClaims(String token) {
        return Jwts.parserBuilder().setSigningKey(getSignKey()).build().parseClaimsJws(token).getBody();
    }

    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }
}
    

张:这段代码看起来挺完整的。那如何在Controller中使用它呢?

李:我们可以添加一个LoginController,处理用户登录请求,并返回JWT Token。

张:好,那代码是怎样的?

李:以下是LoginController的示例代码:

package com.example.researchsystem.controller;

import com.example.researchsystem.security.JwtUtil;
import com.example.researchsystem.model.User;
import com.example.researchsystem.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    private UserService userService;

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public String login(@RequestBody User user) {
        User dbUser = userService.getUserByEmail(user.getEmail());
        if (dbUser != null && dbUser.getPassword().equals(user.getPassword())) {
            return jwtUtil.generateToken(dbUser.getUsername());
        } else {
            return "Invalid credentials";
        }
    }
}
    

张:明白了。那如何在其他接口中校验Token呢?

李:我们可以使用Spring Security的过滤器链,在请求到达Controller之前进行Token校验。

张:那这部分代码应该怎么写?

李:我们可以编写一个JWTFilter类,继承OncePerRequestFilter,重写doFilterInternal方法。

张:好的,那代码是怎样的?

李:以下是JWTFilter的示例代码:

package com.example.researchsystem.security;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        String token = null;
        String username = null;

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            token = authHeader.substring(7);
            username = jwtUtil.extractUsername(token);
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            if (jwtUtil.validateToken(token, userDetails)) {
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }

        filterChain.doFilter(request, response);
    }
}
    

张:这代码应该就能实现Token校验了。那如何将它加入到Spring Security的过滤链中?

李:我们可以创建一个SecurityConfig类,继承WebSecurityConfigurerAdapter,配置相关权限。

张:好的,那代码是怎样的?

李:以下是SecurityConfig的示例代码:

package com.example.researchsystem.config;

import com.example.researchsystem.security.JwtFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFiltersOrder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private JwtFilter jwtFilter;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
            .antMatchers("/api/auth/**").permitAll()
            .anyRequest().authenticated();

        return http.build();
    }
}
    

张:这样整个后端系统就具备了基础的功能和安全性。

李:是的,这只是基础部分。后续还可以扩展更多功能,比如权限管理、日志记录、API文档生成等。

张:感谢你的讲解,我现在对科研系统的后端开发有了更清晰的认识。

李:不客气,希望这些内容对你有帮助。如果有更多问题,随时问我。

智慧校园一站式解决方案

产品报价   解决方案下载   视频教学系列   操作手册、安装部署  

  微信扫码,联系客服