学习进度条
今日所花时间:一小时
今日代码量:100行
博客量:2篇
了解到的知识点:
深入学习androidStudio 完成课堂测试,实现手机端的政策模糊查询
我没有使用AndriodStudio内置的数据库SQLite,而是使用后端服务springboot,创建安全的API端点,在Android中使用Retrofit访问API完成数据库的连接和功能实现
springboot后端代码
实体类代码
package com.example.search.pojo;
import jakarta.persistence.*;
import java.util.Date;
@Entity
@Table(name = "policy")
public class policy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "type")
private String type;
@Column(name = "category")
private String category;
@Column(name = "range")
private String range;
@Column(name = "document")
private String document;
@Column(name = "form")
private String form;
@Column(name = "organ")
private String organ;
@Column(name = "viadata")
private Date viadata;
@Column(name = "pubdata")
private Date pubdata;
@Column(name = "perdata")
private Date perdata;
@Column(name = "field")
private String field;
@Column(name = "theme")
private String theme;
@Column(name = "keyword")
private String keyword;
@Column(name = "superior")
private String superior;
@Column(name = "precursor")
private String precursor;
@Column(name = "succeed")
private String succeed;
@Column(name = "state")
private String state;
@Column(name = "text", columnDefinition = "longtext")
private String text;
@Column(name = "pdf")
private String pdf;
@Column(name = "redundancy")
private String redundancy;
@Column(name = "rank")
private String rank;
@Column(name = "policykey", columnDefinition = "text")
private String policykey;
@Column(name = "newrank")
private String newrank;
@Column(name = "year")
private String year;
@Column(name = "newkey")
private String newkey;
@Column(name = "secondtheme")
private String secondtheme;
@Column(name = "allsum")
private Integer allsum;
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getRange() {
return range;
}
public void setRange(String range) {
this.range = range;
}
public String getDocument() {
return document;
}
public void setDocument(String document) {
this.document = document;
}
public String getForm() {
return form;
}
public void setForm(String form) {
this.form = form;
}
public String getOrgan() {
return organ;
}
public void setOrgan(String organ) {
this.organ = organ;
}
public Date getViadata() {
return viadata;
}
public void setViadata(Date viadata) {
this.viadata = viadata;
}
public Date getPubdata() {
return pubdata;
}
public void setPubdata(Date pubdata) {
this.pubdata = pubdata;
}
public Date getPerdata() {
return perdata;
}
public void setPerdata(Date perdata) {
this.perdata = perdata;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getTheme() {
return theme;
}
public void setTheme(String theme) {
this.theme = theme;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public String getSuperior() {
return superior;
}
public void setSuperior(String superior) {
this.superior = superior;
}
public String getPrecursor() {
return precursor;
}
public void setPrecursor(String precursor) {
this.precursor = precursor;
}
public String getSucceed() {
return succeed;
}
public void setSucceed(String succeed) {
this.succeed = succeed;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getPdf() {
return pdf;
}
public void setPdf(String pdf) {
this.pdf = pdf;
}
public String getRedundancy() {
return redundancy;
}
public void setRedundancy(String redundancy) {
this.redundancy = redundancy;
}
public String getRank() {
return rank;
}
public void setRank(String rank) {
this.rank = rank;
}
public String getPolicykey() {
return policykey;
}
public void setPolicykey(String policykey) {
this.policykey = policykey;
}
public String getNewrank() {
return newrank;
}
public void setNewrank(String newrank) {
this.newrank = newrank;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getNewkey() {
return newkey;
}
public void setNewkey(String newkey) {
this.newkey = newkey;
}
public String getSecondtheme() {
return secondtheme;
}
public void setSecondtheme(String secondtheme) {
this.secondtheme = secondtheme;
}
public Integer getAllsum() {
return allsum;
}
public void setAllsum(Integer allsum) {
this.allsum = allsum;
}
}
Controller层(SelectController)
package com.example.search.controller;
import com.example.search.mapper.SelectMapper;
import com.example.search.pojo.policy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api")
public class select{
@Autowired
private SelectMapper selectMapper;
@GetMapping("/searchPolicies")
@Transactional(readOnly = true)
public ResponseEntity<List<policy>> searchPolicies(
@RequestParam String keyword,
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String organ,
@RequestParam(required = false) String organNot) {
try {
List<policy> policies = selectMapper.findByNameContainingOrKeywordContaining(
keyword,
startDate,
organ,
organNot);
return ResponseEntity.ok(policies);
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}
@GetMapping("/policy/{id}")
@Transactional(readOnly = true)
public ResponseEntity<policy> showPolicyFullText(@PathVariable Long id) {
try {
policy policy = selectMapper.findById(id);
if (policy != null) {
return ResponseEntity.ok(policy);
}
return ResponseEntity.notFound().build();
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}
}
mapper层(selectMapper)
package com.example.search.mapper;
import com.example.search.pojo.PolicyType;
import com.example.search.pojo.policy;
import org.apache.ibatis.annotations.*;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Mapper
public interface SelectMapper {
@SelectProvider(type = PolicySqlProvider.class, method = "findByNameContainingOrKeywordContaining")
@Transactional(readOnly = true)
List<policy> findByNameContainingOrKeywordContaining(
@Param("keyword") String keyword,
@Param("startDate") String startDate,
@Param("organ") String organ,
@Param("organNot") String organNot);
@Select("SELECT * FROM policy WHERE id = #{id}")
@Transactional(readOnly = true)
policy findById(Long id);
}
AndroidStudio代码
创建与springboot的API连接
ApiService
package com.example.day0321search;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.Query;
import java.util.List;
public interface ApiService {
@GET("/api/searchPolicies")
Call<List<Policy>> searchPolicies(@Query("keyword") String keyword);
@GET("/api/policy/{id}")
Call<Policy> getPolicyById(@Path("id") Long id);
}
实体类
package com.example.day0321search;
import java.util.Date;
public class Policy {
private Long id;
private String name;
private String type;
private String category;
private String range;
private String document;
private String form;
private String organ;
private Date viadata;
private Date pubdata;
private Date perdata;
private String field;
private String theme;
private String keyword;
private String superior;
private String precursor;
private String succeed;
private String state;
private String text;
private String pdf;
private String redundancy;
private String rank;
private String policykey;
private String newrank;
private String year;
private String newkey;
private String secondtheme;
private Integer allsum;
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getRange() {
return range;
}
public void setRange(String range) {
this.range = range;
}
public String getDocument() {
return document;
}
public void setDocument(String document) {
this.document = document;
}
public String getForm() {
return form;
}
public void setForm(String form) {
this.form = form;
}
public String getOrgan() {
return organ;
}
public void setOrgan(String organ) {
this.organ = organ;
}
public Date getViadata() {
return viadata;
}
public void setViadata(Date viadata) {
this.viadata = viadata;
}
public Date getPubdata() {
return pubdata;
}
public void setPubdata(Date pubdata) {
this.pubdata = pubdata;
}
public Date getPerdata() {
return perdata;
}
public void setPerdata(Date perdata) {
this.perdata = perdata;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getTheme() {
return theme;
}
public void setTheme(String theme) {
this.theme = theme;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public String getSuperior() {
return superior;
}
public void setSuperior(String superior) {
this.superior = superior;
}
public String getPrecursor() {
return precursor;
}
public void setPrecursor(String precursor) {
this.precursor = precursor;
}
public String getSucceed() {
return succeed;
}
public void setSucceed(String succeed) {
this.succeed = succeed;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getPdf() {
return pdf;
}
public void setPdf(String pdf) {
this.pdf = pdf;
}
public String getRedundancy() {
return redundancy;
}
public void setRedundancy(String redundancy) {
this.redundancy = redundancy;
}
public String getRank() {
return rank;
}
public void setRank(String rank) {
this.rank = rank;
}
public String getPolicykey() {
return policykey;
}
public void setPolicykey(String policykey) {
this.policykey = policykey;
}
public String getNewrank() {
return newrank;
}
public void setNewrank(String newrank) {
this.newrank = newrank;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getNewkey() {
return newkey;
}
public void setNewkey(String newkey) {
this.newkey = newkey;
}
public String getSecondtheme() {
return secondtheme;
}
public void setSecondtheme(String secondtheme) {
this.secondtheme = secondtheme;
}
public Integer getAllsum() {
return allsum;
}
public void setAllsum(Integer allsum) {
this.allsum = allsum;
}
}
RetrofitClient
package com.example.day0321search;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.concurrent.TimeUnit;
public class RetrofitClient {
private static final String BASE_URL = "http://192.168.188.118:8080/";//192.168.188.118写你自己加入的局域网(确保手机和开发电脑在同一局域网下)
private static Retrofit retrofit = null;
public static ApiService getApiService() {
if (retrofit == null) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor)
.build();
// 创建一个宽松模式的Gson实例
Gson gson = new GsonBuilder()
.setLenient()
.create();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
}
return retrofit.create(ApiService.class);
}
}
MainActivity
package com.example.day0321search;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.io.IOException;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
private EditText searchInput;
private RecyclerView policyRecyclerView;
private PolicyAdapter policyAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
searchInput = findViewById(R.id.searchInput);
policyRecyclerView = findViewById(R.id.policyRecyclerView);
policyRecyclerView.setLayoutManager(new LinearLayoutManager(this));
findViewById(R.id.searchButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
searchPolicies();
}
});
}
private void searchPolicies() {
String keyword = searchInput.getText().toString();
ApiService apiService = RetrofitClient.getApiService();
Call<List<Policy>> call = apiService.searchPolicies(keyword);
call.enqueue(new Callback<List<Policy>>() {
@Override
public void onResponse(Call<List<Policy>> call, Response<List<Policy>> response) {
if (response.isSuccessful() && response.body() != null) {
policyAdapter = new PolicyAdapter(response.body());
policyRecyclerView.setAdapter(policyAdapter);
} else {
try {
Log.e("MainActivity", "Response error: " + response.errorBody().string());
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "No policies found", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<List<Policy>> call, Throwable t) {
Log.e("MainActivity", "Network error", t);
Toast.makeText(MainActivity.this, "Network error", Toast.LENGTH_SHORT).show();
}
});
}
}
PolicyAdapter查询政策操作
package com.example.day0321search;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.PolicyViewHolder> {
private List<Policy> policyList;
public PolicyAdapter(List<Policy> policyList) {
this.policyList = policyList;
}
@NonNull
@Override
public PolicyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_policy, parent, false);
return new PolicyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull PolicyViewHolder holder, int position) {
Policy policy = policyList.get(position);
holder.policyName.setText(policy.getName());
// 设置点击事件
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), PolicyDetailActivity.class);
intent.putExtra("policyId", policy.getId());
v.getContext().startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return policyList.size();
}
public static class PolicyViewHolder extends RecyclerView.ViewHolder {
TextView policyName;
public PolicyViewHolder(@NonNull View itemView) {
super(itemView);
policyName = itemView.findViewById(R.id.policyName);
}
}
}
PolicyDatailActivity(政策细节展示)
package com.example.day0321search;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class PolicyDetailActivity extends AppCompatActivity {
private WebView policyWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_policy_detail);
policyWebView = findViewById(R.id.policyWebView);
// 设置 WebView 客户端,确保链接在 WebView 中打开
policyWebView.setWebViewClient(new WebViewClient());
Long policyId = getIntent().getLongExtra("policyId", -1);
if (policyId != -1) {
loadPolicyDetail(policyId);
}
}
private void loadPolicyDetail(Long policyId) {
ApiService apiService = RetrofitClient.getApiService();
Call<Policy> call = apiService.getPolicyById(policyId);
call.enqueue(new Callback<Policy>() {
@Override
public void onResponse(Call<Policy> call, Response<Policy> response) {
if (response.isSuccessful() && response.body() != null) {
String htmlContent = response.body().getText();
// 加载 HTML 内容到 WebView
policyWebView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null);
}
}
@Override
public void onFailure(Call<Policy> call, Throwable t) {
// Handle failure
}
});
}
}
APP页面设计
activity_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=".MainActivity">
<!-- 标题 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="科技政策查询系统"
android:textSize="24sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:paddingTop="20dp"
android:paddingBottom="16dp"/>
<!-- 搜索输入框 -->
<EditText
android:id="@+id/searchInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入政策关键字"
android:inputType="text"
android:maxLines="1"
android:minHeight="48dp" />
<!-- 搜索按钮 -->
<Button
android:id="@+id/searchButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="搜索" />
<!-- 政策列表 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/policyRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp"
tools:listitem="@layout/item_policy" />
</LinearLayout>
item_policy.xml(查询成功页面展示)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
<!-- 政策名称 -->
<TextView
android:id="@+id/policyName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="政策名称"
android:textColor="@android:color/black" />
<!-- 分割线 -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="8dp"
android:background="@android:color/darker_gray" />
</LinearLayout>
activity_policy_detail.xml(政策全全文展示)
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:padding="16dp"
tools:context=".PolicyDetailActivity">
<!-- 使用 WebView 显示政策全文 -->
<WebView
android:id="@+id/policyWebView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>

浙公网安备 33010602011771号