How to get value using Redistemplate in springboot - spring-boot

This is a code that gonna put key and value in Redis
public void putCache(String categoryCode, String subCategoryCode) {
String key = REDIS_KEY + categoryCode + ":" + subCategoryCode;
String value = (String) redisTemplate.opsForValue().get(key);
HashOperations<String, String, String> hash = redisTemplate.opsForHash();
Map<String, String> MapCache = new HashMap<>();
MapCache.put(key,value);
hash.putAll(key,MapCache);
}
When i run the program , it say that my value is null.
How can i fix it? Picture that value in Redis in null
public void spriteGetData() {
List<SpriteEntity> spriteEntity = spriteRepo.findAll();
for (SpriteEntity entities : spriteEntity) {
String categoryCode = entities.getCategoryCode();
String subCategoryCode = entities.getSubCategoryCode();
redisService.putCache(categoryCode, subCategoryCode);
}
This one is use to get data from db and put it in Redis.

Related

How to get the type of values from a JDBC query?

I have a spring batch job that takes in a user query, executes that query to find the selected items, and then I want to insert those items into another database. The problem is that I have to convert elements like dates from the resulting query to insert them again. How can I tell the type of the values returned from the query?
This is what I use to read the items which works properly.
#Bean("querySelectiveItems")
#StepScope
public JdbcCursorItemReader querySelectiveItems(#Qualifier("selectiveSourceDatabase") DataSource dataSource,
#Value("#{jobExecutionContext[" + EtlConfiguration.JOB_PARM_MIGRATION_CONFIG + "]}") MigrationDefinition migrationDefinition
) {
JdbcCursorItemReader reader = new JdbcCursorItemReader<>();
reader.setSql(migrationDefinition.getMigrations().getTable().getQuery());
reader.setDataSource(dataSource);
reader.setRowMapper(new ColumnMapRowMapper());
log.info("Queried for items");
return reader;
}
The following is what I wrote to write to the destination database. The problem is that the values I have to insert are unknown because they are the result of a user query. For example if there is a datatype in my insert statement I must have a TO_DATE around the date value. Is there a way to do this?
#Component
#Lazy
class InsertSelectedItems implements ItemWriter<Map<String, Object>> {
private MigrationDefinition migrationDefinition;
private JdbcTemplate destinationTemplate;
public void setDestinationTemplate(JdbcTemplate destinationTemplate) {
this.destinationTemplate = destinationTemplate;
}
public void setMigrationDefinition(MigrationDefinition migrationDefinition) {
this.migrationDefinition = migrationDefinition;
}
#Override
public void write(List<? extends Map<String, Object>> items) throws Exception {
ArrayList<String> columns = new ArrayList<>();
ArrayList<String> values = new ArrayList<>();
System.out.println(items);
for (Map<String, Object> map : items) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
columns.add(entry.getKey());
values.add(String.valueOf(entry.getValue()));
}
}
String sql = String.format("%s ( %s ) VALUES ( %s ) ",
migrationDefinition.getMigrations().getTable().getInsert(),
String.join(",", columns),
String.join(",", values));
log.info(sql);
destinationTemplate.update(sql);
}
}

spring-data-mongodb aggregation with composite ID

I'm having trouble reading documents from MongoDB using the aggregation framework: I always get null IDs in my results. This only happens for documents that have composite IDs. I tried various versions of spring-data-mongodb (1.10.12, 2.0.7), same result.
Entity definition class
#Document(collection="entities")
public class MyEntity {
static class CompositeKey implements Serializable {
private String stringKey;
private Integer intKey;
public CompositeKey(String stringKey, Integer intKey) {
this.stringKey = stringKey;
this.intKey = intKey;
}
public Integer getIntKey() {
return intKey;
}
public String getStringKey() {
return stringKey;
}
public String toString() {
return "{" + stringKey + " - " + intKey + "}";
}
}
#Id
private CompositeKey id;
private String param;
public MyEntity() {}
public MyEntity(String stringKey, Integer intKey) {
id = new CompositeKey(stringKey, intKey);
}
public CompositeKey getId(){
return id;
}
public void setId(CompositeKey id) {
this.id = id;
}
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
}
Testing code
public static void main(String[] args) {
MongoClient client = new MongoClient("127.0.0.1");
SimpleMongoDbFactory factory = new SimpleMongoDbFactory(client, "aggTest");
MongoTemplate mongoTemplate = new MongoTemplate(factory);
MyEntity entity = new MyEntity();
entity.setId(new MyEntity.CompositeKey("one", 1));
entity.setParam("param1");
mongoTemplate.save(entity);
entity = new MyEntity();
entity.setId(new MyEntity.CompositeKey("two", 2));
entity.setParam("param2");
mongoTemplate.save(entity);
Criteria crit = Criteria.where("param").ne("param3");
List<AggregationOperation> aggOpList = new ArrayList<AggregationOperation>();
aggOpList.add(Aggregation.match(crit));
System.out.println("Documents fetched with find: ");
for (MyEntity aggResult : mongoTemplate.find(new Query(crit), MyEntity.class).toArray(new MyEntity[0]))
System.out.println(aggResult.getId() + " - " + aggResult.getParam());
System.out.println("\nDocuments fetched with aggregate: ");
TypedAggregation<MyEntity> aggregation = new TypedAggregation<>(MyEntity.class, aggOpList);
AggregationResults<MyEntity> aggregate = mongoTemplate.aggregate(aggregation, MyEntity.class);
for (MyEntity aggResult : aggregate.getMappedResults())
System.out.println(aggResult.getId() + " - " + aggResult.getParam());
}
Output
Documents fetched with find:
{one - 1} - param1
{two - 2} - param2
Documents fetched with aggregate:
null - param1
null - param2
Debugging into the following method MappingMongoConverter.read(final MongoPersistentEntity entity, final Document bson, final ObjectPath path) I found that in the first case (find method) the documentAccessor variable has the following contents
Document{{_id=Document{{stringKey=one, intKey=1}}, param=param1, _class=MyEntity}}
whereas in the second case (aggregation query) it looks like
Document{{stringKey=one, intKey=1, param=param1, _class=MyEntity}}
The document gets flattened somehow, which makes it impossible for the converter to populate the ID field. I must be doing something wrong, but what?
Spring Data MongoDB lower than 3.x automatically flatten composite id (fields under composite id are unwrapped and place at root object). This is removed in version 3.0 onwards:
https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#new-features.3.0

How to select several properties for specific name

I am working on a web project using Spring and Spring MVC.
I have a feature that is the same for 3 different elements (which are available in dropdown in view). Only two parameters change for each item. I decided to put these elements and parameters in a .properties file to permit the user change them. So for example in my .properties I have the following:
FC
fcUuid=11111111111111111
fcTag=tag1
AC
itUuid=22222222222222222
itTag=tag2
IT
acUuid=333333333333333333
acTag=tag3
For the moment I am able to retrieve each element separately.
For example:
String communityUuid = SpringPropertiesUtil.getProperty("fcUuid");
(SpringPropertiesUtil extends PropertyPlaceholderConfigurer)
But my question is: how can I retrieve all the parameters relative to one element?
For example the user selects "FC", how in my service layer can I retrieve both fcUuid and fcTag parameters?
Of course I can do something like:
if(param="FC"){
String communityUuid = SpringPropertiesUtil.getProperty("fcUuid");
String communityTag = SpringPropertiesUtil.getProperty("fcTag");
} else if (param="AC"){...}
But I don't want to do that because the user can add elements so I would have to modify the code each time.
I would like something like:
String communityUuid = SpringPropertiesUtil.getProperties(param[0]);
String tagUuid = SpringPropertiesUtil.getProperties(param[1]);
Or even better:
String communityUuid = SpringPropertiesUtil.getProperties(param[uuid]);
String tagUuid = SpringPropertiesUtil.getProperties(param[tag]);
You need customize how to handle properties into map that you need. You can do like :
#group your properites
uiValues=\
FC={fcUuid:11111111111111111},{fcTag : tag1}&&\
AC={itUuid : 22222222222222222},{itTag : tag2}&&\
IT={acUuid:333333333333333333},{acTag:tag3}
#Component
public class ConfigProperties {
//FC=...&&AC=....&&IT=....
private static final String GROUP_SPLITTER = "&&";
private static final String GROUP_VALUES_MARKER = "=";
private static final String START_VALUES_IN_GROUP = "{";
private static final String END_VALUES_IN_GROUP = "}";
private static final String VALUES_SPLITTER= ",";
private static final String KEY_VALUE_SPLITTER= ":";
#Value("#{T(current current package .ConfigProperties).
decodeMap('${uiValues}')}")
private Map<String,Values> map;
/**
if(param="FC"){
String communityUuid = SpringPropertiesUtil.getProperty("fcUuid");
String communityTag = SpringPropertiesUtil.getProperty("fcTag");
}
#Autowired
ConfigProperties configProperties;
String communityUuid = configProperties.getValue("FC","fcUuid");
String communityTag = configProperties.getValue("FC","fcTag");
*/
public String getValue(String key , String property){
//add check for null
Values values= map.get(key);
if (values == null){
return "";
}
for (Tuple tuple : values.tuples){
if (tuple.key.equals(property)){
return tuple.value;
}
}
return "";
}
public List<String> getProperties(String key){
//add check for null
List<String> properties = new ArrayList<>();
Values values= map.get(key);
//add check for null
for (Tuple tuple : values.tuples){
properties.add(tuple.key);
}
return properties;
}
public static Map<String, Values> decodeMap(String value) {
//add validator for value format
boolean isValid = true;
if(!isValid){
return new HashMap<>();
}
Map<String, Values> map = new LinkedHashMap<>();
String[] groups = value.split(GROUP_SPLITTER);
for (String group : groups) {
String[] values = splitToKeyAndValues(group.split(GROUP_VALUES_MARKER)[1]);
String key = group.substring(0,group.indexOf(GROUP_VALUES_MARKER));
map.put(key, getValues(values));
}
return map;
}
private static Values getValues(String[] parts) {
Values values = new Values();
for (int i=0;i<parts.length;i++){
values.tuples.add(getTuple(parts[i]));
}
return values;
}
private static Tuple getTuple(String parts) {
Tuple tuple = new Tuple();
parts = parts.substring(1,parts.length()-1);
tuple.key= parts.split(KEY_VALUE_SPLITTER)[0];
tuple.value= parts.split(KEY_VALUE_SPLITTER)[1];
return tuple;
}
static String[] splitToKeyAndValues(String valuesInGroup) {
return valuesInGroup.split(VALUES_SPLITTER);
}
}
class Values{
List<Tuple> tuples = new ArrayList<>();
}
class Tuple{
String key;
String value;
}
With the help of one of my colleagues I managed to realize that. This is how I proceeded:
In my .properties file I changed the data format, now it looks like:
#FC
clientApplications[0].name=FC
clientApplications[0].communityId=00000000000000
clientApplications[0].tag=tag0
#AC
clientApplications[1].name=AC
clientApplications[1].communityId=11111111111111
clientApplications[1].tag=tag1
etc...
I created a bean named ClientApplication (FC, AC and IT are applications) with 3 attributes (name, communityId and tag)
I created a class named ApplicationStore that stores all the applications present in the propertiesfile in the form of ClientApplication objects and that provides a get method which returns a ClientApplication according to the name of the app.
#Component("applicationStore")
public class ApplicationStore {
private Map<String, ClientApplication> map;
public void put(String key, ClientApplication value) {
map.put(key, value);
}
public ClientApplication get(String key) {
return map.get(key);
}
public ApplicationStore() {
int i = 0;
map = new HashMap<String, ClientApplication>();
while (SpringPropertiesUtil.getProperty("clientApplications[" + i + "].name") != null) {
ClientApplication ca = new ClientApplication();
ca.setName(SpringPropertiesUtil.getProperty("clientApplications[" + i + "].name"));
ca.setCommunityId(SpringPropertiesUtil.getProperty("clientApplications[" + i + "].communityId"));
ca.setTag(SpringPropertiesUtil.getProperty("clientApplications[" + i + "].tag"));
map.put(ca.getName(), ca);
i++;
}
}
}
With that I only have to add this to my service layer:
#Service("aService")
public class AServiceImpl implements AService {
#Autowired
private ApplicationStore apps;
private String communityUuid;
private String communityTag;
#Override
public void aMethod(String appName) trhows Exception {
ClientApplication ca = new ClientApplication();
ca = apps.get(appName);
communityUuid = ca.getCommunityId();
communityTag = ca.getTag();
System.out.println("Application for key " + app + " : " + ca);
System.out.println("communityUuid: " + communityUuid);
System.out.println("communityTag:" + communityTag);
}
}

Spring simplejdbc Stored procedure using resultset Extractor

I am new to Spring and i'm learning it now. Meanwhile i am stuck at a particular place . i am able to execute the stored procedure but its not returning me any result back .please guide me .I'm using sybase database . The stored procedure contains two parameters one is for the input and the other is the output.
public String getGetNextIdQuery(String string, String region){
String custId = "";
JdbcTemplate jtempl = jdbcTemplateMap.get(region);
Map<String, Object> inParams = new HashMap<String, Object>();
String nextId = "?";
inParams.put("len", string);
inParams.put("acct_id",nextId);
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jtempl).
withProcedureName("pr_acct_id")
.withReturnValue()
.withReturnValue().withoutProcedureColumnMetaDataAccess()
.declareParameters(new SqlOutParameter("RETURN", java.sql.Types.VARCHAR))
.declareParameters(new SqlParameter("len", java.sql.Types.SMALLINT))
.declareParameters(new SqlParameter("acct_id", java.sql.Types.VARCHAR))
.declareParameters(new SqlReturnResultSet("RESULT", new ResultSetExtractor<String>() {
#Override
public String extractData(
ResultSet arg0)
throws SQLException {
String custId = "";
int i = 0;
while(arg0.next()) {
System.out.println(i++);
custId = arg0.getString("acct_id");
}
return custId;
}
}));
Map<String, Object> result = simpleJdbcCall.execute(inParams);
System.out.println((String)result.get("RESULT"));
custId = (String)result.get("RESULT");
return custId;
}

How to use #RequestParam(value="foo") Map<MyEnum, String> in Spring Controller?

I want to use some Map<MyEnum, String> as #RequestParam in my Spring Controller. For now I did the following:
public enum MyEnum {
TESTA("TESTA"),
TESTB("TESTB");
String tag;
// constructor MyEnum(String tag) and toString() method omitted
}
#RequestMapping(value = "", method = RequestMethod.POST)
public void x(#RequestParam Map<MyEnum, String> test) {
System.out.println(test);
if(test != null) {
System.out.println(test.size());
for(Entry<MyEnum, String> e : test.entrySet()) {
System.out.println(e.getKey() + " : " + e.getValue());
}
}
}
This acts strange: I just get EVERY Parameter. So if I call the URL with ?FOO=BAR it outputs FOO : BAR. So it definitely takes every String and not just the Strings defined in MyEnum.
So I thought about, why not name the param: #RequestParam(value="foo") Map<MyEnum, String> test. But then I just don't know how to pass the parameters, I always get null.
Or is there any other solution for this?
So if you have a look here: http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/web/bind/annotation/RequestParam.html
It says: If the method parameter is Map<String, String> or MultiValueMap<String, String> and a parameter name is not specified [...]. So it must be possible to use value="foo" and somehow set the values ;)
And: If the method parameter type is Map and a request parameter name is specified, then the request parameter value is converted to a Map assuming an appropriate conversion strategy is available. So where to specify a conversion strategy?
Now I've built a custom solution which works:
#RequestMapping(value = "", method = RequestMethod.POST)
public void x(#RequestParam Map<String, String> all) {
Map<MyEnum, String> test = new HashMap<MyEnum, String>();
for(Entry<String, String> e : all.entrySet()) {
for(MyEnum m : MyEnum.values()) {
if(m.toString().equals(e.getKey())) {
test.put(m, e.getValue());
}
}
}
System.out.println(test);
if(test != null) {
System.out.println(test.size());
for(Entry<MyEnum, String> e : test.entrySet()) {
System.out.println(e.getKey() + " : " + e.getValue());
}
}
}
Would be surely nicer if Spring could handle this...
#RequestParam(value="foo") Map<MyEnum, String>
For Above to work:-
You have to pass values in below format
foo[MyTestA]= bar
foo[MyTestB]= bar2
Now to bind String such as "MyTestA","MyTestB" etc..to your MyEnum
You have to define a converter . Take a look a this link

Resources