学习进度条
今日所花时间:一小时
今日代码量:100行
博客量:1篇
了解到的知识点: 手机端APP开发
对之前个人作业学习APP开发的代码优化
1.完成不同用户登录进入不同页面的功能
页面修改
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".LoginActivity">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="用户登录"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvStudentId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="学号:"
android:layout_marginTop="24dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTitle" />
<EditText
android:id="@+id/etStudentId"
android:layout_width="0dp"
android:layout_height="56dp"
android:hint="输入账号"
android:inputType="text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvStudentId" />
<TextView
android:id="@+id/tvPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密码:"
android:layout_marginTop="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/etStudentId" />
<EditText
android:id="@+id/etPassword"
android:layout_width="0dp"
android:layout_height="56dp"
android:hint="输入密码"
android:inputType="textPassword"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvPassword" />
<!-- 在密码输入框和登录按钮之间添加角色选择 -->
<RadioGroup
android:id="@+id/rgRole"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/etPassword">
<RadioButton
android:id="@+id/rbStudent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="学生"
android:checked="true"/>
<RadioButton
android:id="@+id/rbTeacher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="教师"
android:layout_marginLeft="16dp"/>
</RadioGroup>
<Button
android:id="@+id/btnLogin"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginTop="100dp"
android:text="登录"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/etPassword" />
<Button
android:id="@+id/btnRegister"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginTop="24dp"
android:text="注册"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnLogin" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_teacher_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".TeacherMainActivity">
<!-- 标题 -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="学生每日打卡记录"
android:textSize="24sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="16dp"/>
<!-- 表格标题行 -->
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="*"
android:background="#f0f0f0">
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="学号"
android:textStyle="bold"
android:gravity="center"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="日期"
android:textStyle="bold"
android:gravity="center"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="PSP阶段"
android:textStyle="bold"
android:gravity="center"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="耗时(分钟)"
android:textStyle="bold"
android:gravity="center"/>
</TableRow>
</TableLayout>
<!-- 记录列表 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="vertical"/>
<!-- 按钮部分保持不变 -->
<Button
android:id="@+id/btnExport"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="导出数据"
android:layout_marginTop="8dp"/>
<Button
android:id="@+id/btnSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="每日总结查询"
android:layout_marginTop="8dp"/>
<Button
android:id="@+id/btnStudentController"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="学生总结管理"
android:layout_marginTop="8dp"/>
<Button
android:id="@+id/LoginOut"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="退出登录"
android:layout_marginTop="8dp"/>
</LinearLayout>
LoginActivity,登录(根据不同用户)跳转
package com.example.study0327;
// LoginActivity.java
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.study0327.api.ApiService;
import com.example.study0327.api.RetrofitClient;
import com.example.study0327.pojo.ApiResponse;
import com.example.study0327.utils.JwtUtil;
import java.util.Map;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class LoginActivity extends AppCompatActivity {
private EditText etStudentId, etPassword,etRole;
private Button btnLogin, btnRegister;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// 检查是否已登录
if (isLoggedIn()) {
// 获取存储的角色
SharedPreferences prefs = getSharedPreferences("user_prefs", MODE_PRIVATE);
String role = prefs.getString("user_role", null);
if (role != null) {
navigateToMain(role);
}
return;
}
initViews();
setupLoginButton();
setupRegisterButton(); // 新增注册按钮事件绑定
}
private void initViews() {
etStudentId = findViewById(R.id.etStudentId);
etPassword = findViewById(R.id.etPassword);
btnLogin = findViewById(R.id.btnLogin);
btnRegister = findViewById(R.id.btnRegister); // 初始化注册按钮
}
private void setupLoginButton() {
btnLogin.setOnClickListener(v -> attemptLogin());
}
private void setupRegisterButton() {
btnRegister.setOnClickListener(v -> {
// 跳转到注册页面
Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
startActivity(intent);
});
}
// 获取选择的角色
private String getSelectedRole() {
RadioGroup rgRole = findViewById(R.id.rgRole);
return rgRole.getCheckedRadioButtonId() == R.id.rbTeacher ? "TEACHER" : "STUDENT";
}
private void attemptLogin() {
String studentId = etStudentId.getText().toString().trim();
String password = etPassword.getText().toString().trim();
String role = getSelectedRole(); // 获取用户选择的角色
if (studentId.isEmpty() || password.isEmpty()) {
Toast.makeText(this, "学号和密码不能为空", Toast.LENGTH_SHORT).show();
return;
}
showLoading(true);
ApiService apiService = RetrofitClient.getClient().create(ApiService.class);
Call<ApiResponse<String>> call = apiService.loginUser(studentId, password,role);
call.enqueue(new Callback<ApiResponse<String>>() {
@Override
public void onResponse(Call<ApiResponse<String>> call, Response<ApiResponse<String>> response) {
showLoading(false);
if (response.isSuccessful() && response.body() != null) {
ApiResponse<String> apiResponse = response.body();
if (apiResponse.getCode() == 1) { // 登录成功
String token = apiResponse.getData();
// 解析Token获取角色(需确保后端JWT包含role字段)
Map<String, Object> claims = JwtUtil.parseToken(token); // 需实现JwtUtil解析
String role = (String) claims.get("role");
// 调试输出:确认角色值
Log.d("LoginDebug", "Role from token: " + role);
saveLoginState(token, studentId, role); // 传递studentId
navigateToMain(role);
Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(LoginActivity.this, apiResponse.getMessage(), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(LoginActivity.this, "登录失败: " + response.message(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<ApiResponse<String>> call, Throwable t) {
showLoading(false);
Toast.makeText(LoginActivity.this, "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
private boolean isLoggedIn() {
SharedPreferences prefs = getSharedPreferences("user_prefs", MODE_PRIVATE);
return prefs.contains("auth_token");
}
private void saveLoginState(String token, String studentId, String role) {
SharedPreferences.Editor editor = getSharedPreferences("user_prefs", MODE_PRIVATE).edit();
editor.putString("auth_token", token);
editor.putString("student_id", studentId); // 保存student_id
editor.putString("user_role", role); // 保存角色
editor.putBoolean("is_logged_in", true);
editor.apply();
}
private void navigateToMain(String role) {
Intent intent;
if ("TEACHER".equals(role)) {
intent = new Intent(LoginActivity.this, TeacherMainActivity.class); // 教师专属主页
} else {
intent = new Intent(LoginActivity.this, MainActivity.class); // 学生主页
}
startActivity(intent);
finish();
}
private void showLoading(boolean show) {
// 这里可以添加加载动画的显示/隐藏逻辑
btnLogin.setEnabled(!show);
}
}
MainActivity
package com.example.study0327;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE_SET_GOAL = 1001; // 添加这行定义请求码
private Button btnLogin;
private Button btnRegister;
private LinearLayout layoutFunctions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLogin = findViewById(R.id.btnLogin);
btnRegister = findViewById(R.id.btnRegister);
layoutFunctions = findViewById(R.id.layoutFunctions);
checkLoginStatus();
btnLogin.setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
});
btnRegister.setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, RegisterActivity.class);
startActivity(intent);
});
// 在onCreate方法中添加
// Button btnTeacherRegister = findViewById(R.id.btnTeacherRegister);
// btnTeacherRegister.setOnClickListener(v -> {
// Intent intent = new Intent(MainActivity.this, TeacherRegisterActivity.class);
// startActivity(intent);
// });
}
private void checkLoginStatus() {
SharedPreferences prefs = getSharedPreferences("user_prefs", MODE_PRIVATE);
boolean isLoggedIn = prefs.getBoolean("is_logged_in", false);
String role = prefs.getString("user_role", "STUDENT"); // 默认学生
if (isLoggedIn) {
if ("TEACHER".equals(role)) {
startActivity(new Intent(this, TeacherMainActivity.class));
finish();
} else {
btnLogin.setVisibility(View.GONE);
btnRegister.setVisibility(View.GONE);
layoutFunctions.setVisibility(View.VISIBLE);
setupFunctionButtons();
}
} else {
btnLogin.setVisibility(View.VISIBLE);
btnRegister.setVisibility(View.VISIBLE);
layoutFunctions.setVisibility(View.GONE);
}
}
private void setupFunctionButtons() {
findViewById(R.id.btnAddRecord).setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, AddRecordActivity.class);
startActivity(intent);
});
findViewById(R.id.btnAddSummary).setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, AddSummaryActivity.class);
startActivity(intent);
});
findViewById(R.id.btnSetGoal).setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, SetGoalActivity.class);
startActivityForResult(intent, REQUEST_CODE_SET_GOAL); // 使用定义好的请求码
});
findViewById(R.id.btnLogout).setOnClickListener(v -> {
logout();
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_SET_GOAL && resultCode == RESULT_OK) {
Toast.makeText(this, "目标设置成功", Toast.LENGTH_SHORT).show();
}
}
private void logout() {
SharedPreferences.Editor editor = getSharedPreferences("user_prefs", MODE_PRIVATE).edit();
editor.remove("auth_token");
editor.putBoolean("is_logged_in", false);
editor.apply();
checkLoginStatus();
}
private void navigateBasedOnRole(String role) {
Intent intent;
if ("TEACHER".equals(role)) {
intent = new Intent(this, TeacherMainActivity.class);
} else {
intent = new Intent(this, MainActivity.class);
}
startActivity(intent);
}
}
TeacherMainActivity
package com.example.study0327;
import android.Manifest;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.widget.Button;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.study0327.api.ApiService;
import com.example.study0327.api.RetrofitClient;
import com.example.study0327.modules.ProgrammingRecord;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class TeacherMainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ProgrammingRecordAdapter adapter;
private Button btnExport, btnSearch, btnStudentController, btnLogout;
private static final int REQUEST_WRITE_EXTERNAL_STORAGE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_teacher_main);
// 初始化视图
recyclerView = findViewById(R.id.recyclerView);
btnExport = findViewById(R.id.btnExport);
btnSearch = findViewById(R.id.btnSearch);
btnStudentController = findViewById(R.id.btnStudentController);
btnLogout = findViewById(R.id.LoginOut);
adapter = new ProgrammingRecordAdapter();
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// 加载数据
loadAllRecords();
// 导出按钮点击事件
btnExport.setOnClickListener(v -> exportData());
// 查询按钮点击事件
btnSearch.setOnClickListener(v -> {
Intent intent = new Intent(TeacherMainActivity.this, DailySummarySearchActivity.class);
startActivity(intent);
});
// 学生管理按钮点击事件
btnStudentController.setOnClickListener(v -> {
Toast.makeText(this, "跳转到学生总结管理", Toast.LENGTH_SHORT).show();
});
// 退出登录按钮点击事件
btnLogout.setOnClickListener(v -> logout());
}
private void loadAllRecords() {
String token = "Bearer " + getSharedPreferences("user_prefs", MODE_PRIVATE)
.getString("auth_token", "");
ApiService apiService = RetrofitClient.getClient().create(ApiService.class);
Call<List<ProgrammingRecord>> call = apiService.getAllProgrammingRecords(token);
call.enqueue(new Callback<List<ProgrammingRecord>>() {
@Override
public void onResponse(Call<List<ProgrammingRecord>> call, Response<List<ProgrammingRecord>> response) {
if (response.isSuccessful() && response.body() != null) {
List<ProgrammingRecord> sortedRecords = response.body().stream()
.sorted((r1, r2) -> r2.getRecordDate().compareTo(r1.getRecordDate()))
.collect(Collectors.toList());
adapter.setRecords(sortedRecords);
} else {
Toast.makeText(TeacherMainActivity.this, "获取数据失败", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<List<ProgrammingRecord>> call, Throwable t) {
Toast.makeText(TeacherMainActivity.this, "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
private void exportData() {
// 对于Android 10及以上版本,使用应用专属存储不需要权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// Android 10+可以直接写入应用专属目录
showExportOptions();
} else {
// Android 9及以下需要请求权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_WRITE_EXTERNAL_STORAGE);
} else {
showExportOptions();
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_WRITE_EXTERNAL_STORAGE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showExportOptions();
} else {
Toast.makeText(this, "需要存储权限才能导出数据", Toast.LENGTH_SHORT).show();
// 可选:解释为什么需要这个权限
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(this)
.setTitle("权限说明")
.setMessage("需要存储权限将数据导出到下载文件夹")
.setPositiveButton("确定", (dialog, which) ->
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_WRITE_EXTERNAL_STORAGE))
.setNegativeButton("取消", null)
.show();
}
}
}
}
private void showExportOptions() {
new AlertDialog.Builder(this)
.setTitle("选择导出格式")
.setItems(new String[]{"CSV格式", "Excel格式"}, (dialog, which) -> {
if (which == 0) {
exportToCSV();
} else {
exportToExcel();
}
})
.show();
}
private void exportToCSV() {
if (adapter.getItemCount() == 0) {
Toast.makeText(this, "没有数据可导出", Toast.LENGTH_SHORT).show();
return;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault());
String fileName = "学生打卡记录_" + sdf.format(new Date()) + ".csv";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// Android 10+使用应用专属目录
File dir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
File file = new File(dir, fileName);
writeFile(file);
} else {
// Android 9及以下使用传统方法
File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
File file = new File(downloadsDir, fileName);
writeFile(file);
}
}
private void writeFile(File file) {
try {
FileWriter writer = new FileWriter(file);
writer.append("学号,日期,PSP阶段,耗时(分钟),内容\n");
for (ProgrammingRecord record : adapter.getRecords()) {
writer.append(String.format("%s,%s,%s,%d,%s\n",
record.getUserId(),
record.getRecordDate(),
record.getPspStage(),
record.getTimeSpent(),
record.getContent() != null ? record.getContent().replace(",", ",") : ""));
}
writer.flush();
writer.close();
Toast.makeText(this, "数据已导出到: " + file.getAbsolutePath(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "导出失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void exportToExcel() {
if (adapter.getItemCount() == 0) {
Toast.makeText(this, "没有数据可导出", Toast.LENGTH_SHORT).show();
return;
}
try {
// 创建工作簿
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("学生打卡记录");
// 创建表头
HSSFRow headerRow = sheet.createRow(0);
headerRow.createCell(0).setCellValue("学号");
headerRow.createCell(1).setCellValue("日期");
headerRow.createCell(2).setCellValue("PSP阶段");
headerRow.createCell(3).setCellValue("耗时(分钟)");
headerRow.createCell(4).setCellValue("内容");
// 填充数据
int rowNum = 1;
for (ProgrammingRecord record : adapter.getRecords()) {
HSSFRow row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(record.getUserId());
row.createCell(1).setCellValue(record.getRecordDate());
row.createCell(2).setCellValue(record.getPspStage());
row.createCell(3).setCellValue(record.getTimeSpent());
row.createCell(4).setCellValue(record.getContent() != null ? record.getContent() : "");
}
// 自动调整列宽
for (int i = 0; i < 5; i++) {
sheet.autoSizeColumn(i);
}
// 保存文件
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault());
String fileName = "学生打卡记录_" + sdf.format(new Date()) + ".xls";
File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
File file = new File(downloadsDir, fileName);
FileOutputStream outputStream = new FileOutputStream(file);
workbook.write(outputStream);
workbook.close();
outputStream.close();
Toast.makeText(this, "数据已导出到: " + file.getAbsolutePath(), Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "导出失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void logout() {
SharedPreferences.Editor editor = getSharedPreferences("user_prefs", MODE_PRIVATE).edit();
editor.remove("auth_token");
editor.remove("student_id");
editor.remove("user_role");
editor.putBoolean("is_logged_in", false);
editor.apply();
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();
}
}
2.教师能够看见所有学生用户的每日打卡记录
ProgrammingRecordController
package com.example.studydemo.controller;
import com.example.studydemo.mapper.ProgrammingRecordMapper;
import com.example.studydemo.pojo.DailySummary;
import com.example.studydemo.pojo.ProgrammingRecord;
import com.example.studydemo.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/programmingRecord")
public class ProgrammingRecordController {
@Autowired
private ProgrammingRecordMapper programmingRecordMapper;
@PostMapping("/addRecord")
public ResponseEntity<String> addProgrammingRecord(@RequestBody ProgrammingRecord programmingRecord,
@RequestHeader("Authorization") String token) {
try {
// 从token中解析用户信息
String studentId = JwtUtil.parseToken(token).get("student_id").toString();
if (studentId == null) {
return ResponseEntity.badRequest().body("未获取到用户学号");
}
// 设置用户ID为学号
programmingRecord.setUserId(Long.parseLong(studentId));
// 验证其他字段
if (programmingRecord.getRecordDate() == null) {
return ResponseEntity.badRequest().body("记录日期不能为空");
}
if (programmingRecord.getPspStage() == null || programmingRecord.getPspStage().trim().isEmpty()) {
return ResponseEntity.badRequest().body("PSP阶段不能为空");
}
int insertedRows = programmingRecordMapper.insertProgrammingRecord(programmingRecord);
if (insertedRows > 0) {
return ResponseEntity.ok("编程记录添加成功");
} else {
return ResponseEntity.badRequest().body("编程记录添加失败");
}
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.badRequest().body("添加编程记录出错: " + e.getMessage());
}
}
@GetMapping("/list")
public ResponseEntity<List<ProgrammingRecord>> listProgrammingRecord(@RequestHeader("Authorization") String token) {
try {
Map<String,Object> claims = JwtUtil.parseToken(token);
String studentIdStr = (String) claims.get("student_id");
if (studentIdStr == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
String studentId = String.valueOf(Long.parseLong(studentIdStr));
List<ProgrammingRecord> record = programmingRecordMapper.selectProgrammingRecordByUserId(studentId);
return ResponseEntity.ok(record);
}catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@GetMapping("/listAll")
public ResponseEntity<List<ProgrammingRecord>> listAllRecords(
@RequestHeader("Authorization") String token
) {
try {
// 验证Token并检查角色
Map<String, Object> claims = JwtUtil.parseToken(token);
String role = (String) claims.get("role");
if (!"TEACHER".equals(role)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
// 教师可查询所有记录
List<ProgrammingRecord> records = programmingRecordMapper.selectAllRecords();
return ResponseEntity.ok(records);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
ViewRecordsActivity
package com.example.study0327;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.study0327.api.ApiService;
import com.example.study0327.api.RetrofitClient;
import com.example.study0327.modules.ProgrammingRecord;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ViewRecordsActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ProgrammingRecordAdapter adapter;
private String token;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_records);
// 获取token
SharedPreferences prefs = getSharedPreferences("user_prefs", MODE_PRIVATE);
token = "Bearer " + prefs.getString("auth_token", "").trim();
// 初始化RecyclerView
recyclerView = findViewById(R.id.recyclerViewRecords);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new ProgrammingRecordAdapter();
recyclerView.setAdapter(adapter);
// 加载数据
loadProgrammingRecords();
}
private void loadProgrammingRecords() {
ApiService apiService = RetrofitClient.getClient().create(ApiService.class);
Call<List<ProgrammingRecord>> call = apiService.getProgrammingRecords(token);
call.enqueue(new Callback<List<ProgrammingRecord>>() {
@Override
public void onResponse(Call<List<ProgrammingRecord>> call, Response<List<ProgrammingRecord>> response) {
if (response.isSuccessful() && response.body() != null) {
adapter.setRecords(response.body());
} else {
Toast.makeText(ViewRecordsActivity.this, "获取记录失败: " + response.message(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<List<ProgrammingRecord>> call, Throwable t) {
Toast.makeText(ViewRecordsActivity.this, "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}

浙公网安备 33010602011771号